Skip to content

Commit 091946d

Browse files
BridgeARpabloerhard
authored andcommitted
test(setup): arm a 120s watchdog to turn exit-hangs into fast failures (#9056)
A `before` hook that throws after starting the tracer leaves the RC socket and background timers running. Mocha (run without --exit) never drains the event loop, and the job silently hits the 45-minute job timeout rather than reporting the real error. The watchdog times out 120 s after all suites complete, logs the active handles, and exits non-zero so the error surfaces immediately. It is unref'd so a clean run always exits before the timer fires. The 120 s window is 4× the longest observed test timeout (30 s) and is measured from the end of all teardown, so no legitimate per-suite after hook races it.
1 parent 247bbb3 commit 091946d

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

packages/dd-trace/test/setup/mocha.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,12 @@ function insertVersionDep (dir, pkgName, version) {
413413

414414
const ORIGINAL_PROCESS_EXIT = process.exit
415415

416+
// The watchdog fires if the process fails to exit after all suites have finished. The typical cause is a `before`
417+
// hook that throws after starting the tracer — the `agent.load` / RC socket stays open, mocha drains no further,
418+
// and the job silently times out. 120 s is well above the longest real per-suite teardown (≤30 s observed) so clean
419+
// runs always exit before it triggers; only a leaked handle — the actual bug — fires it.
420+
const EXIT_WATCHDOG_MS = 120_000
421+
416422
exports.mochaHooks = {
417423
beforeAll () {
418424
process.exit = (code) => {
@@ -421,6 +427,20 @@ exports.mochaHooks = {
421427
},
422428
afterAll () {
423429
process.exit = ORIGINAL_PROCESS_EXIT
430+
431+
// Arm the watchdog after restoring process.exit so it can call it.
432+
const watchdog = setTimeout(() => {
433+
// eslint-disable-next-line no-console
434+
console.error(
435+
`[dd-trace test watchdog] Process did not exit ${EXIT_WATCHDOG_MS / 1000}s after all suites completed.`,
436+
'Active handles keeping the event loop alive:',
437+
process._getActiveHandles?.()?.map(h => h?.constructor?.name ?? String(h))
438+
)
439+
ORIGINAL_PROCESS_EXIT(1)
440+
}, EXIT_WATCHDOG_MS)
441+
442+
// Unref so a clean run (no leak) always exits without waiting for the timer.
443+
watchdog.unref()
424444
},
425445
afterEach () {
426446
if (_agent) _agent.reset()

0 commit comments

Comments
 (0)