diff --git a/packages/cloudflare/src/client.ts b/packages/cloudflare/src/client.ts index 050d89f39dbd..80c6a9b0322c 100644 --- a/packages/cloudflare/src/client.ts +++ b/packages/cloudflare/src/client.ts @@ -34,6 +34,7 @@ export class CloudflareClient extends ServerRuntimeClient { // TODO: Grab version information runtime: { name: 'cloudflare' }, // TODO: Add server name + _flushInterval: 0, }; super(clientOptions); diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index dc56b6f22a3c..12b590636384 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -137,18 +137,21 @@ function setupWeightBasedFlushing< if (weight >= 800_000) { flushFn(client); } else if (!isTimerActive) { - // Only start timer if one isn't already running. - // This prevents flushing being delayed by items that arrive close to the timeout limit - // and thus resetting the flushing timeout and delaying items being flushed. - isTimerActive = true; - // Use safeUnref so the timer doesn't prevent the process from exiting - flushTimeout = safeUnref( - setTimeout(() => { - flushFn(client); - // Note: isTimerActive is reset by the flushHook handler above, not here, - // to avoid race conditions when new items arrive during the flush. - }, DEFAULT_FLUSH_INTERVAL), - ); + const flushInterval = client.getOptions()._flushInterval ?? DEFAULT_FLUSH_INTERVAL; + if (flushInterval > 0) { + // Only start timer if one isn't already running. + // This prevents flushing being delayed by items that arrive close to the timeout limit + // and thus resetting the flushing timeout and delaying items being flushed. + isTimerActive = true; + // Use safeUnref so the timer doesn't prevent the process from exiting + flushTimeout = safeUnref( + setTimeout(() => { + flushFn(client); + // Note: isTimerActive is reset by the flushHook handler above, not here, + // to avoid race conditions when new items arrive during the flush. + }, flushInterval), + ); + } } }); diff --git a/packages/core/src/types-hoist/options.ts b/packages/core/src/types-hoist/options.ts index db65585d9e43..366fd30547f4 100644 --- a/packages/core/src/types-hoist/options.ts +++ b/packages/core/src/types-hoist/options.ts @@ -590,6 +590,18 @@ export interface ClientOptions { expect(flushMetricsHandler).toHaveBeenCalledTimes(1); }); + + it('does not create a flush timer when _flushInterval is 0', () => { + const safeUnrefSpy = vi.spyOn(timerModule, 'safeUnref'); + + const options = getDefaultTestClientOptions({ + dsn: PUBLIC_DSN, + _flushInterval: 0, + }); + const client = new TestClient(options); + const scope = new Scope(); + scope.setClient(client); + + _INTERNAL_captureMetric({ name: 'test_metric', value: 42, type: 'counter', attributes: {} }, { scope }); + + expect(safeUnrefSpy).not.toHaveBeenCalled(); + + safeUnrefSpy.mockRestore(); + }); + + it('still flushes metrics via flush event when _flushInterval is 0', () => { + const options = getDefaultTestClientOptions({ + dsn: PUBLIC_DSN, + _flushInterval: 0, + }); + const client = new TestClient(options); + const scope = new Scope(); + scope.setClient(client); + + const sendEnvelopeSpy = vi.spyOn(client, 'sendEnvelope'); + + _INTERNAL_captureMetric({ name: 'metric1', value: 1, type: 'counter', attributes: {} }, { scope }); + + expect(sendEnvelopeSpy).not.toHaveBeenCalled(); + + client.emit('flush'); + + expect(sendEnvelopeSpy).toHaveBeenCalledTimes(1); + }); + + it('still flushes metrics on size threshold when _flushInterval is 0', () => { + const options = getDefaultTestClientOptions({ + dsn: PUBLIC_DSN, + _flushInterval: 0, + }); + const client = new TestClient(options); + const scope = new Scope(); + scope.setClient(client); + + const sendEnvelopeSpy = vi.spyOn(client, 'sendEnvelope'); + + const largeValue = 'x'.repeat(400_000); + _INTERNAL_captureMetric( + { name: 'large_metric', value: 1, type: 'counter', attributes: { large_value: largeValue } }, + { scope }, + ); + + expect(sendEnvelopeSpy).toHaveBeenCalledTimes(1); + }); }); describe('promise buffer usage', () => { diff --git a/packages/vercel-edge/src/client.ts b/packages/vercel-edge/src/client.ts index ab7a4e938e96..d72f5f2f6718 100644 --- a/packages/vercel-edge/src/client.ts +++ b/packages/vercel-edge/src/client.ts @@ -30,6 +30,7 @@ export class VercelEdgeClient extends ServerRuntimeClient