test(anr): Use pure-JS busy work so ANR stack samples capture longWork#22133
Open
mydea wants to merge 1 commit into
Open
test(anr): Use pure-JS busy work so ANR stack samples capture longWork#22133mydea wants to merge 1 commit into
mydea wants to merge 1 commit into
Conversation
The ANR tests intermittently failed because the captured stacktrace was missing the required `longWork` frame — the sample showed only `node:internal/timers` frames instead. Root cause: `longWork` blocked the event loop via `crypto.pbkdf2Sync`, a native addon call. The ANR worker samples the main thread through the inspector, which can only pause at a JS safepoint — V8 cannot pause inside a native call, so the pause resolves only after `pbkdf2Sync` returns. When ANR fired near the tail of `longWork`, the pause landed after the call returned and control had popped back to the timer dispatch, so the sampled stack missed `longWork` entirely. Replace the native crypto busy-work with a pure-JS CPU loop in every ANR scenario (both node-core and node integration tests). V8 can now sample inside `longWork`, so it reliably appears on the captured stack. `longWork` stays defined locally in each scenario to preserve the per-file `filename` assertions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
isaacs
approved these changes
Jul 10, 2026
isaacs
left a comment
Member
There was a problem hiding this comment.
LGTM. The math seems kind of unnecessary, but harmless.
| const start = Date.now(); | ||
| let n = 1; | ||
| while (Date.now() - start < 1000) { | ||
| n = (n * 1103515245 + 12345) % 2147483648; |
Member
There was a problem hiding this comment.
This math seems kind of silly? It's not significantly different than just n++, since it's going to run about 35M times in a second, regardless. The more costly work is just the Date.now() check.
timfish
approved these changes
Jul 10, 2026
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.
The ANR integration tests intermittently failed because the captured stacktrace was missing the required
longWorkframe — the sample showed onlynode:internal/timersframes (processTimers/listOnTimeout/insert) instead, anddebug_metawas absent.Root cause:
longWorkblocked the event loop viacrypto.pbkdf2Sync, a native addon call. The ANR worker samples the main thread through the inspector, which can only pause at a JS safepoint — V8 cannot pause inside a native call, so the pause resolves only afterpbkdf2Syncreturns. When ANR fired near the tail oflongWork, the pause landed after the call had returned and control had popped back to the timer dispatch, so the sampled stack missedlongWorkentirely.longWorkblocks ~880ms locally (well over the 100ms threshold), so this was a sampling-boundary race, not a too-short block.This replaces the native crypto busy-work with a pure-JS CPU loop in every ANR scenario, across both the node-core and node integration test suites. V8 can now sample inside
longWork, so it reliably appears on the captured stack.longWorkstays defined locally in each scenario to preserve the per-filefilenameassertions (e.g.isolated.mjs).Verified locally: both suites pass 12/12 across repeated runs.
Fixes #21702
🤖 Generated with Claude Code