diff --git a/dev-packages/node-integration-tests/suites/metrics/should-exit-forced.js b/dev-packages/node-integration-tests/suites/metrics/should-exit-forced.js new file mode 100644 index 000000000000..2621828973ab --- /dev/null +++ b/dev-packages/node-integration-tests/suites/metrics/should-exit-forced.js @@ -0,0 +1,19 @@ +const Sentry = require('@sentry/node'); + +function configureSentry() { + Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + autoSessionTracking: false, + }); + + Sentry.metrics.increment('test'); +} + +async function main() { + configureSentry(); + await new Promise(resolve => setTimeout(resolve, 1000)); + process.exit(0); +} + +main(); diff --git a/dev-packages/node-integration-tests/suites/metrics/should-exit.js b/dev-packages/node-integration-tests/suites/metrics/should-exit.js new file mode 100644 index 000000000000..01a6f0194507 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/metrics/should-exit.js @@ -0,0 +1,18 @@ +const Sentry = require('@sentry/node'); + +function configureSentry() { + Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + autoSessionTracking: false, + }); + + Sentry.metrics.increment('test'); +} + +async function main() { + configureSentry(); + await new Promise(resolve => setTimeout(resolve, 1000)); +} + +main(); diff --git a/dev-packages/node-integration-tests/suites/metrics/test.ts b/dev-packages/node-integration-tests/suites/metrics/test.ts new file mode 100644 index 000000000000..2c3cc350eeba --- /dev/null +++ b/dev-packages/node-integration-tests/suites/metrics/test.ts @@ -0,0 +1,21 @@ +import { createRunner } from '../../utils/runner'; + +describe('metrics', () => { + test('should exit', done => { + const runner = createRunner(__dirname, 'should-exit.js').start(); + + setTimeout(() => { + expect(runner.childHasExited()).toBe(true); + done(); + }, 5_000); + }); + + test('should exit forced', done => { + const runner = createRunner(__dirname, 'should-exit-forced.js').start(); + + setTimeout(() => { + expect(runner.childHasExited()).toBe(true); + done(); + }, 5_000); + }); +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/metric-summaries/scenario.js b/dev-packages/node-integration-tests/suites/tracing/metric-summaries/scenario.js index e2921db180af..422fa4c504a5 100644 --- a/dev-packages/node-integration-tests/suites/tracing/metric-summaries/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/metric-summaries/scenario.js @@ -8,9 +8,6 @@ Sentry.init({ transport: loggingTransport, }); -// Stop the process from exiting before the transaction is sent -setInterval(() => {}, 1000); - Sentry.startSpan( { name: 'Test Transaction', diff --git a/packages/core/src/metrics/aggregator.ts b/packages/core/src/metrics/aggregator.ts index 169e40b42905..8b56d190b88a 100644 --- a/packages/core/src/metrics/aggregator.ts +++ b/packages/core/src/metrics/aggregator.ts @@ -20,7 +20,9 @@ export class MetricsAggregator implements MetricsAggregatorBase { // that we store in memory. private _bucketsTotalWeight; - private readonly _interval: ReturnType; + // Cast to any so that it can use Node.js timeout + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private readonly _interval: any; // SDKs are required to shift the flush interval by random() * rollup_in_seconds. // That shift is determined once per startup to create jittering. @@ -37,7 +39,13 @@ export class MetricsAggregator implements MetricsAggregatorBase { public constructor(private readonly _client: Client) { this._buckets = new Map(); this._bucketsTotalWeight = 0; - this._interval = setInterval(() => this._flush(), DEFAULT_FLUSH_INTERVAL); + + this._interval = setInterval(() => this._flush(), DEFAULT_FLUSH_INTERVAL) as any; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (this._interval.unref) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + this._interval.unref(); + } this._flushShift = Math.floor((Math.random() * DEFAULT_FLUSH_INTERVAL) / 1000); this._forceFlush = false; } diff --git a/packages/core/src/sessionflusher.ts b/packages/core/src/sessionflusher.ts index 604a654a6b01..291864333119 100644 --- a/packages/core/src/sessionflusher.ts +++ b/packages/core/src/sessionflusher.ts @@ -20,7 +20,9 @@ export class SessionFlusher implements SessionFlusherLike { public readonly flushTimeout: number; private _pendingAggregates: Record; private _sessionAttrs: ReleaseHealthAttributes; - private _intervalId: ReturnType; + // Cast to any so that it can use Node.js timeout + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private _intervalId: any; private _isEnabled: boolean; private _client: Client; @@ -30,8 +32,13 @@ export class SessionFlusher implements SessionFlusherLike { this._pendingAggregates = {}; this._isEnabled = true; - // Call to setInterval, so that flush is called every 60 seconds + // Call to setInterval, so that flush is called every 60 seconds. this._intervalId = setInterval(() => this.flush(), this.flushTimeout * 1000); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (this._intervalId.unref) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + this._intervalId.unref(); + } this._sessionAttrs = attrs; }