Conversation
Collaborator
|
Review requested:
|
jasnell
force-pushed
the
jasnell/process-timeout
branch
2 times, most recently
from
September 19, 2026 17:54
7ae9d38 to
b846293
Compare
jasnell
force-pushed
the
jasnell/process-timeout
branch
from
September 19, 2026 19:25
b846293 to
f0d5d08
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #66138 +/- ##
==========================================
- Coverage 90.29% 90.25% -0.04%
==========================================
Files 790 790
Lines 271882 272369 +487
Branches 51899 52004 +105
==========================================
+ Hits 245485 245836 +351
- Misses 16888 16996 +108
- Partials 9509 9537 +28
🚀 New features to boost your workflow:
|
Collaborator
Putting a time limit on a Node.js process is common in many
use cases, but each of the common approaches are generally
flawed.
OS and CI timeouts are inconsistent and blind. Every OS flavor
handles process timeouts in different ways. Stock macOS and
Windows do not ship coreutils `timeout`, etc. None of the options
can explain why the process was still running or what exactly
was interrupted. Using setTimeout only fires when the event loop
is free so it misses busy loops and thread blocks and cannot
see the stack. Diagnostics triggered by signal have the same
problem.
This introduces a `--process-timeout` that should work
consistently across all runtimes. A native watchdog thread
interrupts the main thread, even in the middle of running
code. It prints the JavaScript stack (if any) and resources
keeping the event loop alive (if any), and can optionally
print a full diagnostic report. The process exits with a
distinct code (124). If the main thread is stuck in native
code, the process still exits.
$ node --process-timeout=10s -e "while(true) {}"
(node:483970) Process timed out after 10s (--process-timeout). Exiting with code 124.
Main thread was executing JavaScript:
at [eval]:1:1
at runScriptInThisContext (node:internal/vm:219:10)
at node:internal/process/execution:485:12
at [eval]-wrapper:6:24
at runScriptInContext (node:internal/process/execution:483:60)
at evalFunction (node:internal/process/execution:317:30)
at evalTypeScript (node:internal/process/execution:329:3)
at node:internal/main/eval_string:71:3
No resources keeping the event loop alive were found.
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
jasnell
force-pushed
the
jasnell/process-timeout
branch
from
September 20, 2026 15:37
f0d5d08 to
4a3abcd
Compare
Collaborator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Putting a time limit on a Node.js process is common in many use cases, but each of the common approaches are generally flawed.
OS and CI timeouts are inconsistent and blind. Every OS flavor handles process timeouts in different ways. Stock macOS and Windows do not ship coreutils
timeout, etc. None of the options can explain why the process was still running or what exactly was interrupted. Using setTimeout only fires when the event loop is free so it misses busy loops and thread blocks and cannot see the stack. Diagnostics triggered by signal have the same problem.This introduces a
--process-timeoutthat should work consistently across all runtimes. A native watchdog thread interrupts the main thread, even in the middle of running code. It prints the JavaScript stack (if any) and resources keeping the event loop alive (if any), and can optionally print a full diagnostic report. The process exits with a distinct code (124). If the main thread is stuck in native code, the process still exits.Compare with using
timeoutwhich produces no diagnostic output:This needs careful review and evaluation before considering landing. There are ways that the timeout can interplay with various other options (like
--watch, and--inspect). I've made some preliminary decisions on it but they need to be reviewed.We will need to evaluate flakiness of the tests... there are a couple risks to look out for: