Skip to content

Commit 6b0d9fe

Browse files
feat(core): adds support for onPluginReadyError hook
* Adds `onPluginReadyError` which is passed as a `catch` of each plugin's `ready()` call.
1 parent fef1830 commit 6b0d9fe

File tree

4 files changed

+73
-3
lines changed

4 files changed

+73
-3
lines changed

.changeset/rare-pillows-warn.md

Lines changed: 6 additions & 0 deletions
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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,57 @@ describe('Initialization', () => {
207207
expect(ready).toHaveBeenCalled()
208208
})
209209

210+
it('ready method is called even when plugin errors on ready, and calls `onPluginReadyError`', 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+
}
246+
)
247+
248+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
249+
const promise = analytics.ready(ready)
250+
expect(lazyPlugin1.load).toHaveBeenCalled()
251+
expect(lazyPlugin2.load).toHaveBeenCalled()
252+
expect(ready).not.toHaveBeenCalled()
253+
254+
await sleep(100)
255+
expect(ready).toHaveBeenCalled()
256+
expect(onPluginReadyError).toHaveBeenCalledTimes(1)
257+
258+
return promise
259+
})
260+
210261
describe('cdn', () => {
211262
it('should get the correct CDN in plugins if the CDN overridden', async () => {
212263
const overriddenCDNUrl = 'http://cdn.segment.com' // http instead of https

packages/browser/src/browser/settings.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ export interface InitOptions {
224224
plan?: Plan
225225
retryQueue?: boolean
226226
obfuscate?: boolean
227+
228+
/** Error handling function for when an integration fails */
229+
onPluginReadyError?: (error: Error) => Promise<void>
230+
227231
/**
228232
* This callback allows you to update/mutate CDN Settings.
229233
* This is called directly after settings are fetched from the CDN.

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,18 @@ export class Analytics
534534
async ready(
535535
callback: Function = (res: Promise<unknown>[]): Promise<unknown>[] => res
536536
): Promise<unknown> {
537-
return Promise.all(
538-
this.queue.plugins.map((i) => (i.ready ? i.ready() : Promise.resolve()))
539-
).then((res) => {
537+
return Promise.allSettled(
538+
this.queue.plugins.map((i) =>
539+
i.ready
540+
? i.ready().catch(this.options.onPluginReadyError)
541+
: Promise.resolve()
542+
)
543+
).then((results) => {
544+
const res = results.map((result) => {
545+
if (result.status === 'fulfilled') {
546+
return result.value
547+
}
548+
})
540549
callback(res)
541550
return res
542551
})

0 commit comments

Comments
 (0)