src: fix --process-timeout message when exit waits · nodejs/node@edbff8c · GitHub
Skip to content

Commit edbff8c

Browse files
trivikraduh95
authored andcommitted
src: fix --process-timeout message when exit waits
process.exit(), uncaught exceptions and unhandled rejections exit through Environment::Exit(), which never calls OnEnvironmentStopping(). If a Worker blocked in a synchronous native call held up that exit past the deadline, the watchdog blamed the main thread. Check Environment::is_stopping() and report that the process did not finish exiting instead. Signed-off-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Assisted-by: claude:opus-5.5 PR-URL: #66361 Fixes: #66360 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com>
1 parent 14cc587 commit edbff8c

3 files changed

Lines changed: 71 additions & 11 deletions

File tree

‎src/node_watchdog.cc‎

Lines changed: 26 additions & 9 deletions
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
// Exits the process while a Worker is blocked in a synchronous native call, so
3+
// that exiting the process waits for the Worker. The first argument is a path
4+
// at which a file is created once the process is exiting. The second argument
5+
// is how the process exits: 'exit' calls process.exit(), 'throw' throws an
6+
// uncaught exception, and 'reject' leaves a promise rejection unhandled.
7+
const fs = require('fs');
8+
const path = require('path');
9+
const { Worker } = require('worker_threads');
10+
11+
const [, , marker, mode] = process.argv;
12+
const childMarker = `${marker}.child`;
13+
const script = path.join(__dirname, 'wait-for-parent.js');
14+
const args = [script, String(process.pid), childMarker];
15+
new Worker(`
16+
require('child_process').execFileSync(process.execPath, ${JSON.stringify(args)}, {
17+
stdio: 'ignore',
18+
});
19+
`, { eval: true });
20+
21+
// Once the child process has created its file, the Worker is blocked in
22+
// execFileSync() and can no longer be terminated.
23+
const interval = setInterval(() => {
24+
if (!fs.existsSync(childMarker)) return;
25+
clearInterval(interval);
26+
if (mode === 'throw') throw new Error('boom');
27+
if (mode === 'reject') return Promise.reject(new Error('boom'));
28+
process.exit(0);
29+
}, 10);
30+
31+
process.on('exit', () => fs.writeFileSync(marker, ''));

‎test/parallel/test-process-timeout-blocked.js‎

Lines changed: 14 additions & 2 deletions

0 commit comments

Comments
 (0)