From 29c791b801afcfd03aab45fdb01c621608ef0fd1 Mon Sep 17 00:00:00 2001 From: Tim Yiu <137842098+tyiuhc@users.noreply.github.com> Date: Tue, 29 Apr 2025 16:00:34 -0700 Subject: [PATCH 1/2] fix: Poll for plugin readiness --- .../src/integration/manager.ts | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/experiment-browser/src/integration/manager.ts b/packages/experiment-browser/src/integration/manager.ts index 109e8b51..a706f518 100644 --- a/packages/experiment-browser/src/integration/manager.ts +++ b/packages/experiment-browser/src/integration/manager.ts @@ -174,7 +174,9 @@ export class PersistentTrackingQueue { private readonly isLocalStorageAvailable = isLocalStorageAvailable(); private inMemoryQueue: ExperimentEvent[] = []; private poller: any | undefined; + private readyCheckInterval: any | undefined; private tracker: ((event: ExperimentEvent) => boolean) | undefined; + private isReady = false; constructor(instanceName: string, maxQueueSize: number = MAX_QUEUE_SIZE) { this.storageKey = `EXP_unsent_${instanceName}`; @@ -184,20 +186,42 @@ export class PersistentTrackingQueue { push(event: ExperimentEvent): void { this.loadQueue(); this.inMemoryQueue.push(event); - this.flush(); + if (this.isReady) { + this.flush(); + } this.storeQueue(); + this.startReadyCheck(); } setTracker(tracker: (event: ExperimentEvent) => boolean): void { this.tracker = tracker; + this.startPolling(); + this.loadFlushStore(); + } + + private startReadyCheck(): void { + if (this.readyCheckInterval || !this.tracker) return; + + this.readyCheckInterval = safeGlobal.setInterval(() => { + if (this.tracker!(this.inMemoryQueue[0])) { + this.isReady = true; + safeGlobal.clearInterval(this.readyCheckInterval); + this.readyCheckInterval = undefined; + this.flush(); + } + }, 50); + } + + private startPolling(): void { + if (this.poller) return; + this.poller = safeGlobal.setInterval(() => { this.loadFlushStore(); }, 1000); - this.loadFlushStore(); } private flush(): void { - if (!this.tracker) return; + if (!this.tracker || !this.isReady) return; if (this.inMemoryQueue.length === 0) return; for (const event of this.inMemoryQueue) { if (!this.tracker(event)) return; @@ -218,7 +242,6 @@ export class PersistentTrackingQueue { private storeQueue(): void { if (this.isLocalStorageAvailable) { - // Trim the queue if it is too large. if (this.inMemoryQueue.length > this.maxQueueSize) { this.inMemoryQueue = this.inMemoryQueue.slice( this.inMemoryQueue.length - this.maxQueueSize, From 4926895ca49dcae82aa07af991a189f848a1b676 Mon Sep 17 00:00:00 2001 From: Tim Yiu <137842098+tyiuhc@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:02:02 -0700 Subject: [PATCH 2/2] fix: set ready upon init --- .../src/integration/manager.ts | 34 +++++++++---------- .../test/integration/manager.test.ts | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/experiment-browser/src/integration/manager.ts b/packages/experiment-browser/src/integration/manager.ts index a706f518..8cd8f9b1 100644 --- a/packages/experiment-browser/src/integration/manager.ts +++ b/packages/experiment-browser/src/integration/manager.ts @@ -54,24 +54,22 @@ export class IntegrationManager { * @param integration the integration to manage. */ setIntegration(integration: IntegrationPlugin): void { - if (this.integration && this.integration.teardown) { + if (this.integration?.teardown) { void this.integration.teardown(); } this.integration = integration; - if (integration.setup) { - this.integration.setup(this.config, this.client).then( - () => { - this.queue.setTracker(this.integration.track.bind(integration)); - this.resolve(); - }, - () => { - this.queue.setTracker(this.integration.track.bind(integration)); - this.resolve(); - }, - ); - } else { + + const finalizeSetup = () => { this.queue.setTracker(this.integration.track.bind(integration)); this.resolve(); + }; + + if (integration.setup) { + void this.integration + .setup(this.config, this.client) + .finally(finalizeSetup); + } else { + finalizeSetup(); } } @@ -186,11 +184,13 @@ export class PersistentTrackingQueue { push(event: ExperimentEvent): void { this.loadQueue(); this.inMemoryQueue.push(event); - if (this.isReady) { + if (this.tracker) { + this.isReady = true; this.flush(); + } else { + this.startReadyCheck(); } this.storeQueue(); - this.startReadyCheck(); } setTracker(tracker: (event: ExperimentEvent) => boolean): void { @@ -203,13 +203,13 @@ export class PersistentTrackingQueue { if (this.readyCheckInterval || !this.tracker) return; this.readyCheckInterval = safeGlobal.setInterval(() => { - if (this.tracker!(this.inMemoryQueue[0])) { + if (this.tracker) { this.isReady = true; safeGlobal.clearInterval(this.readyCheckInterval); this.readyCheckInterval = undefined; this.flush(); } - }, 50); + }, 25); } private startPolling(): void { diff --git a/packages/experiment-browser/test/integration/manager.test.ts b/packages/experiment-browser/test/integration/manager.test.ts index 6fccb911..f2f03e2d 100644 --- a/packages/experiment-browser/test/integration/manager.test.ts +++ b/packages/experiment-browser/test/integration/manager.test.ts @@ -18,6 +18,7 @@ describe('IntegrationManager', () => { // @ts-ignore const client = { test: 'client' } as ExperimentClient; manager = new IntegrationManager(config, client); + (manager as any).isReady = true; }); describe('ready', () => {