Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2

### :bug: Bug Fixes

* fix(core): avoid leaking Node.js types via `unrefTimer()` util [#5986](https://github.com/open-telemetry/opentelemetry-js/pull/5986)
* fix(core): avoid leaking Node.js types via otperformance [#5987](https://github.com/open-telemetry/opentelemetry-js/pull/5987) @pichlermarc
* **important:** this bug fix may be breaking for certain uses of `otperformnace`
* `otperformance.now()` and `otperformance.timeOrigin` are not affected.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
ExportResultCode,
getNumberFromEnv,
globalErrorHandler,
unrefTimer,
BindOnceFuture,
internal,
callWithTimeout,
Expand All @@ -40,7 +39,7 @@ export abstract class BatchLogRecordProcessorBase<T extends BufferConfig>
private readonly _exportTimeoutMillis: number;

private _finishedLogRecords: SdkLogRecord[] = [];
private _timer: NodeJS.Timeout | undefined;
private _timer: NodeJS.Timeout | number | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are removing NodeJS.Timer type in src/common/timer-util.ts but this private property still holds NodeJS.Timeout. I've checked the type signature and saw that NodeJS.Timeout extends NodeJS.Timer. Should we replace the type here as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be safe to keep. The private property's type gets erased in the final type definition. As a consequence, /// <reference types="node" /> does not end up in the BatchLogRecordProcessor.d.ts :)

import type { BufferConfig } from '../types'; import type { SdkLogRecord } from './SdkLogRecord'; import type { LogRecordExporter } from './LogRecordExporter'; import type { LogRecordProcessor } from '../LogRecordProcessor'; export declare abstract class BatchLogRecordProcessorBase<T extends BufferConfig> implements LogRecordProcessor { private readonly _exporter; private readonly _maxExportBatchSize; private readonly _maxQueueSize; private readonly _scheduledDelayMillis; private readonly _exportTimeoutMillis; private _finishedLogRecords; private _timer; private _shutdownOnce; constructor(_exporter: LogRecordExporter, config?: T); onEmit(logRecord: SdkLogRecord): void; forceFlush(): Promise<void>; shutdown(): Promise<void>; private _shutdown; /** Add a LogRecord in the buffer. */ private _addToBuffer; /**  * Send all LogRecords to the exporter respecting the batch size limit  * This function is used only on forceFlush or shutdown,  * for all other cases _flush should be used  * */ private _flushAll; private _flushOneBatch; private _maybeStartTimer; private _clearTimer; private _export; protected abstract onShutdown(): void; } //# sourceMappingURL=BatchLogRecordProcessorBase.d.ts.map
private _shutdownOnce: BindOnceFuture<void>;

constructor(
Expand Down Expand Up @@ -162,7 +161,11 @@ export abstract class BatchLogRecordProcessorBase<T extends BufferConfig>
globalErrorHandler(e);
});
}, this._scheduledDelayMillis);
unrefTimer(this._timer);

// depending on runtime, this may be a 'number' or NodeJS.Timeout
if (typeof this._timer !== 'number') {
this._timer.unref();
}
}

private _clearTimer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export function unrefTimer(timer: NodeJS.Timer): void {
timer.unref();

/**
* @deprecated please copy this code to your implementation instead, this function will be removed in the next major version of this package.
* @param timer
*/
export function unrefTimer(timer: { unref(): unknown } | number): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it is worth to keep this and make the argument a Refable, like https://nodejs.org/api/process.html#processunrefmayberefable, so that we can reduce the repetitiveness.

if (typeof timer !== 'number') {
timer.unref();
}
}
2 changes: 1 addition & 1 deletion packages/opentelemetry-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export {
millisToHrTime,
timeInputToHrTime,
} from './common/time';
export { unrefTimer } from './common/timer-util';
export type { ErrorHandler, InstrumentationScope } from './common/types';
export { ExportResultCode } from './ExportResult';
export type { ExportResult } from './ExportResult';
Expand All @@ -49,7 +50,6 @@ export {
getNumberFromEnv,
getStringListFromEnv,
otperformance,
unrefTimer,
} from './platform';
export { CompositePropagator } from './propagation/composite';
export type { CompositePropagatorConfig } from './propagation/composite';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,3 @@ export {
export { _globalThis } from './globalThis';
export { otperformance } from './performance';
export { SDK_INFO } from './sdk-info';
export { unrefTimer } from './timer-util';
1 change: 0 additions & 1 deletion packages/opentelemetry-core/src/platform/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export {
SDK_INFO,
_globalThis,
otperformance,
unrefTimer,
getBooleanFromEnv,
getStringFromEnv,
getNumberFromEnv,
Expand Down
1 change: 0 additions & 1 deletion packages/opentelemetry-core/src/platform/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,3 @@ export {
export { _globalThis } from './globalThis';
export { otperformance } from './performance';
export { SDK_INFO } from './sdk-info';
export { unrefTimer } from './timer-util';
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export function unrefTimer(_timer: number): void {}

import { unrefTimer } from '../../../src';
import * as sinon from 'sinon';

describe('timer-util', function () {
it('does not throw on number', function () {
unrefTimer(1);
});

it('does call unref', function () {
const unrefStub = sinon.stub();
unrefTimer({ unref: unrefStub });
sinon.assert.calledOnce(unrefStub);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
getNumberFromEnv,
globalErrorHandler,
suppressTracing,
unrefTimer,
} from '@opentelemetry/core';
import { Span } from '../Span';
import { SpanProcessor } from '../SpanProcessor';
Expand All @@ -43,7 +42,7 @@ export abstract class BatchSpanProcessorBase<T extends BufferConfig>

private _isExporting = false;
private _finishedSpans: ReadableSpan[] = [];
private _timer: NodeJS.Timeout | undefined;
private _timer: NodeJS.Timeout | number | undefined;
private _shutdownOnce: BindOnceFuture<void>;
private _droppedSpansCount: number = 0;

Expand Down Expand Up @@ -249,7 +248,11 @@ export abstract class BatchSpanProcessorBase<T extends BufferConfig>
}
if (this._timer !== undefined) return;
this._timer = setTimeout(() => flush(), this._scheduledDelayMillis);
unrefTimer(this._timer);

// depending on runtime, this may be a 'number' or NodeJS.Timeout
if (typeof this._timer !== 'number') {
this._timer.unref();
}
}

private _clearTimer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
internal,
ExportResultCode,
globalErrorHandler,
unrefTimer,
} from '@opentelemetry/core';
import { MetricReader } from './MetricReader';
import { PushMetricExporter } from './MetricExporter';
Expand Down Expand Up @@ -153,7 +152,11 @@ export class PeriodicExportingMetricReader extends MetricReader {
// this._runOnce never rejects. Using void operator to suppress @typescript-eslint/no-floating-promises.
void this._runOnce();
}, this._exportInterval);
unrefTimer(this._interval);

// depending on runtime, this may be a 'number' or NodeJS.Timeout
if (typeof this._interval !== 'number') {
this._interval.unref();
}
}

protected async onForceFlush(): Promise<void> {
Expand Down