Skip to content

Commit 9ce37d2

Browse files
feat(core): adds flag to allow analytics.ready() to run even if plugin fails on ready
1 parent 4e0cb63 commit 9ce37d2

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

.changeset/rare-pillows-warn.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@segment/analytics-next': minor
3+
---
4+
5+
Adds a new option `ignorePluginReadyError` which prevents `analytics.ready` failure when a plugin fails to be ready.
6+
Also adds another option `onPluginReadyError` which allows developers to handle the plugin failures at ready stage.

packages/browser/src/browser/__tests__/integration.test.ts

+52
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,58 @@ describe('Initialization', () => {
207207
expect(ready).toHaveBeenCalled()
208208
})
209209

210+
it('ready method is called plugin errors on ready and `runReadyOnIntegrationError` is true', async () => {
211+
const ready = jest.fn()
212+
const onPluginReadyError = jest.fn()
213+
214+
const lazyPlugin1: Plugin = {
215+
name: 'Test 2',
216+
type: 'destination',
217+
version: '1.0',
218+
219+
load: async (_ctx) => {},
220+
ready: async () => {
221+
return new Promise((resolve) => setTimeout(resolve, 100))
222+
},
223+
isLoaded: () => true,
224+
}
225+
226+
const lazyPlugin2: Plugin = {
227+
name: 'Test 2',
228+
type: 'destination',
229+
version: '1.0',
230+
231+
load: async (_ctx) => {},
232+
ready: () => Promise.reject('failed readying'),
233+
isLoaded: () => true,
234+
}
235+
236+
jest.spyOn(lazyPlugin1, 'load')
237+
jest.spyOn(lazyPlugin2, 'load')
238+
const [analytics] = await AnalyticsBrowser.load(
239+
{
240+
writeKey,
241+
plugins: [lazyPlugin1, lazyPlugin2, xt],
242+
},
243+
{
244+
onPluginReadyError,
245+
ignorePluginReadyError: true,
246+
}
247+
)
248+
249+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
250+
const promise = analytics.ready(ready)
251+
expect(lazyPlugin1.load).toHaveBeenCalled()
252+
expect(lazyPlugin2.load).toHaveBeenCalled()
253+
expect(ready).not.toHaveBeenCalled()
254+
255+
await sleep(100)
256+
expect(ready).toHaveBeenCalled()
257+
expect(onPluginReadyError).toHaveBeenCalledTimes(1)
258+
259+
return promise
260+
})
261+
210262
describe('cdn', () => {
211263
it('should get the correct CDN in plugins if the CDN overridden', async () => {
212264
const overriddenCDNUrl = 'http://cdn.segment.com' // http instead of https

packages/browser/src/browser/settings.ts

+7
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,13 @@ export interface InitOptions {
224224
plan?: Plan
225225
retryQueue?: boolean
226226
obfuscate?: boolean
227+
228+
/** Enables the possibility to trigger .ready() even in case some integrations fail */
229+
ignorePluginReadyError?: boolean
230+
231+
/** Error handling function for when an integration fails */
232+
onPluginReadyError?: (error: Error) => Promise<void>
233+
227234
/**
228235
* This callback allows you to update/mutate CDN Settings.
229236
* This is called directly after settings are fetched from the CDN.

packages/browser/src/core/analytics/index.ts

+18
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,24 @@ export class Analytics
534534
async ready(
535535
callback: Function = (res: Promise<unknown>[]): Promise<unknown>[] => res
536536
): Promise<unknown> {
537+
if (this.options.ignorePluginReadyError) {
538+
return Promise.allSettled(
539+
this.queue.plugins.map((i) =>
540+
i.ready
541+
? i.ready().catch(this.options.onPluginReadyError)
542+
: Promise.resolve()
543+
)
544+
).then((results) => {
545+
const res = results.map((result) => {
546+
if (result.status === 'fulfilled') {
547+
return result.value
548+
}
549+
})
550+
callback(res)
551+
return res
552+
})
553+
}
554+
537555
return Promise.all(
538556
this.queue.plugins.map((i) => (i.ready ? i.ready() : Promise.resolve()))
539557
).then((res) => {

0 commit comments

Comments
 (0)