diff --git a/packages/client-http/src/ApplyManager.test.ts b/packages/client-http/src/ApplyManager.test.ts index a625a25d..132ea945 100644 --- a/packages/client-http/src/ApplyManager.test.ts +++ b/packages/client-http/src/ApplyManager.test.ts @@ -14,6 +14,7 @@ describe('ApplyManager', () => { beforeEach(() => { instanceUnderTest = new ApplyManager({ timeout: 100, + maxBufferSize: 3, client: mockClient, }); resolveMock.mockResolvedValue({}); @@ -99,4 +100,31 @@ describe('ApplyManager', () => { 'some-token2', ); }); + + it('should send apply event when the max buffer size is met, and flush the apply events', async () => { + const applyTime = new Date().toISOString(); + + instanceUnderTest.apply('some-token', 'apply-test'); + instanceUnderTest.apply('some-token', 'apply-test1'); + instanceUnderTest.apply('some-token', 'apply-test2'); + + expect(resolveMock).toHaveBeenCalledTimes(1); + expect(resolveMock).toHaveBeenCalledWith( + [ + { + flag: 'flags/apply-test', + applyTime: applyTime, + }, + { + flag: 'flags/apply-test1', + applyTime: applyTime, + }, + { + flag: 'flags/apply-test2', + applyTime: applyTime, + }, + ], + 'some-token', + ); + }); }); diff --git a/packages/client-http/src/ApplyManager.ts b/packages/client-http/src/ApplyManager.ts index bd64cb4c..72197377 100644 --- a/packages/client-http/src/ApplyManager.ts +++ b/packages/client-http/src/ApplyManager.ts @@ -2,6 +2,7 @@ import { ConfidenceClient, AppliedFlag } from './client'; export interface ApplyManagerOptions { timeout: number; + maxBufferSize: number; client: ConfidenceClient; } @@ -9,11 +10,13 @@ export class ApplyManager { private resolveTokenPending: Map = new Map(); private resolveTokenSeen: Map> = new Map(); private readonly timeout: number; + private readonly maxBufferSize: number; private client: ConfidenceClient; private flushTimeout: ReturnType | null = null; constructor(options: ApplyManagerOptions) { this.timeout = options.timeout; + this.maxBufferSize = options.maxBufferSize; this.client = options.client; } @@ -61,6 +64,11 @@ export class ApplyManager { if (this.flushTimeout) { clearTimeout(this.flushTimeout); } - this.flushTimeout = setTimeout(() => this.flush(), this.timeout); + + if ((this.resolveTokenPending.get(resolveToken)?.length || 0) >= this.maxBufferSize) { + this.flush(); + } else { + this.flushTimeout = setTimeout(() => this.flush(), this.timeout); + } } } diff --git a/packages/openfeature-web-provider/src/ConfidenceWebProvider.ts b/packages/openfeature-web-provider/src/ConfidenceWebProvider.ts index 7aeab382..2284954e 100644 --- a/packages/openfeature-web-provider/src/ConfidenceWebProvider.ts +++ b/packages/openfeature-web-provider/src/ConfidenceWebProvider.ts @@ -16,6 +16,7 @@ import equal from 'fast-deep-equal'; import { ApplyManager, ConfidenceClient, Configuration, ResolveContext } from '@spotify-confidence/client-http'; const APPLY_TIMEOUT = 250; +const MAX_APPLY_BUFFER_SIZE = 20; export interface ConfidenceWebProviderOptions { apply: 'access' | 'backend'; @@ -35,7 +36,11 @@ export class ConfidenceWebProvider implements Provider { constructor(client: ConfidenceClient, options: ConfidenceWebProviderOptions) { this.client = client; if (options.apply !== 'backend') { - this.applyManager = new ApplyManager({ client: this.client, timeout: APPLY_TIMEOUT }); + this.applyManager = new ApplyManager({ + client: this.client, + timeout: APPLY_TIMEOUT, + maxBufferSize: MAX_APPLY_BUFFER_SIZE, + }); } }