Skip to content

Commit

Permalink
Merge pull request #148 from Flagsmith/fix/concurrent-analytics-flush
Browse files Browse the repository at this point in the history
fix: only flush analytics once if requested concurrently
  • Loading branch information
rolodato authored Apr 29, 2024
2 parents ad2127c + 1688ec9 commit 3b3a078
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
10 changes: 7 additions & 3 deletions sdk/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class AnalyticsProcessor {
analyticsData: { [key: string]: any };
private requestTimeoutMs: number = 3000;
private logger: Logger;
private currentFlush: ReturnType<typeof fetch> | undefined;

/**
* AnalyticsProcessor is used to track how often individual Flags are evaluated within
Expand All @@ -35,25 +36,28 @@ export class AnalyticsProcessor {
* Sends all the collected data to the api asynchronously and resets the timer
*/
async flush() {
if (!Object.keys(this.analyticsData).length) {
if (this.currentFlush || !Object.keys(this.analyticsData).length) {
return;
}

try {
await fetch(this.analyticsEndpoint, {
this.currentFlush = fetch(this.analyticsEndpoint, {
method: 'POST',
body: JSON.stringify(this.analyticsData),
timeout: this.requestTimeoutMs,
headers: {
'Content-Type': 'application/json',
'X-Environment-Key': this.environmentKey
}
})
});
await this.currentFlush;
} catch (error) {
// We don't want failing to write analytics to cause any exceptions in the main
// thread so we just swallow them here.
this.logger.warn('Failed to post analytics to Flagsmith API. Not clearing data, will retry.')
return;
} finally {
this.currentFlush = undefined;
}

this.analyticsData = {};
Expand Down
18 changes: 18 additions & 0 deletions tests/sdk/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,21 @@ test('errors in fetch sending analytics data are swallowed', async () => {
// we expect that fetch was called but the exception was handled
expect(fetch).toHaveBeenCalled();
})

test('analytics is only flushed once even if requested concurrently', async () => {
const processor = analyticsProcessor();
processor.trackFeature('myFeature');
// @ts-ignore
fetch.mockImplementation(() => {
return new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
});
const flushes = Promise.all([
processor.flush(),
processor.flush(),
])
jest.runOnlyPendingTimers();
await flushes;
expect(fetch).toHaveBeenCalledTimes(1)
})

0 comments on commit 3b3a078

Please sign in to comment.