Skip to content

feat: let flush() stop waiting on an AbortSignal - #41

Merged
bengl merged 1 commit into
nodejs:mainfrom
bengl:bengl/flush-signal
Nov 4, 2026
Merged

bengl merged 1 commit into
nodejs:mainfrom
bengl:bengl/flush-signal

Conversation

@bengl

@bengl bengl commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Follows #32, which made flush() return a promise, and adds a way to bound how long it waits.

What changed. flush({ signal }) takes an AbortSignal, such as AbortSignal.timeout(ms), the way Node core APIs take one. When it aborts, the promise rejects with an AbortError shaped like core's: code ABORT_ERR, message The operation was aborted, and the signal's reason as its cause. Core builds that error from an internal class, so microtel builds the same shape. Export failures still resolve the promise, so only an abort the caller asked for rejects.

Aborting stops the waiting, not the export. The export keeps running, bounded by exportTimeout, and its spans still reach the collector if it succeeds. With a signal that has already aborted, the promise rejects right away and no export starts, so the spans stay buffered for the next flush. The listener goes on through addAbortListener(), so it runs even when an earlier listener stops the event's propagation, as core's own abort listeners do. It comes off once the flush settles, so one signal can serve many flushes.

Validation. Options must be an object and signal an AbortSignal, checked the way core checks them. validateAbortSignal is ported from core into lib/validate.js, with parity tests against core's own. The beforeExit handler now calls flush() with no arguments, since Node passes it the exit code.

Not taken. A separate timeout option. AbortSignal.timeout() already covers it.

Tests. In test/test-flush-promise.js:

  • no signal, and empty options, behave as before
  • invalid options and an invalid signal throw ERR_INVALID_ARG_TYPE
  • an already-aborted signal rejects and leaves the spans for a later flush, which exports them
  • aborting while an export is in flight rejects right away, and the export still finishes. The collector holds its answer until after the rejection, so a flush that waited instead would deadlock the child. A flush started after the abort stays pending until the held export is answered.
  • the flush still rejects when an earlier abort listener stops propagation
  • AbortSignal.timeout() rejects with its TimeoutError as the cause
  • the abort listener is gone once flush() settles

@bengl
bengl force-pushed the bengl/flush-signal branch from 3baa541 to 334538a Compare November 4, 2026 14:02
@bengl
bengl requested a review from a team November 4, 2026 14:30
@bengl
bengl marked this pull request as ready for review November 4, 2026 14:31
@bengl
bengl force-pushed the bengl/flush-signal branch from 334538a to 0bd2b34 Compare November 4, 2026 17:25
Previously, a caller could not bound how long flush() waited. Now
flush({ signal }) takes an AbortSignal, such as AbortSignal.timeout(ms),
the way core APIs take one, and rejects with an AbortError shaped like
core's when it aborts. Export failures still resolve the promise.

Aborting stops the waiting, not the export, which keeps running,
bounded by exportTimeout. With a signal that has already aborted,
flush() rejects right away and starts no export, so the spans stay
buffered for the next flush. The abort listener runs even when an
earlier listener stops the event's propagation, as core's do.

validateAbortSignal is ported from core into lib/validate.js, with
parity tests.

The guarded beforeExit flush calls flush() with no arguments, since
Node passes the exit code, which flush() would reject as its options.
The beforeExit test reads the payload the child already delivered, so
a broken beforeExit flush fails it rather than hanging it.

Signed-off-by: Bryan English <bryan@bryanenglish.com>
@bengl
bengl force-pushed the bengl/flush-signal branch from 0bd2b34 to dd9af8a Compare November 4, 2026 19:55
@bengl
bengl merged commit fbfc847 into nodejs:main Nov 4, 2026
6 checks passed
@bengl
bengl deleted the bengl/flush-signal branch November 4, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants