ci: disable node test runner process isolation to stop flaky failures - #28
Merged
Conversation
…lures The node test runner's default process isolation spawns the test file as a child process and parses the child's stdout pipe for v8-serialized test events. Tests that spawn OS processes with inherited stdio make those grandchildren write raw bytes into that same pipe, and a write landing mid-frame corrupts the framing, failing the whole file with "Unable to deserialize cloned data due to invalid or unsupported version" (see nodejs/node#64061). It's timing-dependent and worst on macOS where pipe writes are only atomic up to 512 bytes. deno-test funnels all test files through a single runner file, so process isolation buys nothing. With --test-isolation=none the tests run in the main process and there is no serialization pipe to corrupt.
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.
Problem
The
test:nodetask fails intermittently on CI (worst on macOS) with:Root cause
With the node test runner's default process isolation,
node --testspawns the test file as a child process and parses the child's stdout pipe for v8-serialized test events (2-byte v8 header + 4-byte length + payload). Tests in this repo spawn real OS processes withstdio: "inherit", so those grandchildren write raw bytes directly into that same pipe, concurrently with the serializer. The parser tolerates raw bytes between frames (that's why the stray5/1/2lines normally print fine), but a write landing mid-frame corrupts the framing and fails the entire file. It's timing-dependent, hence flaky — and macOS is the worst case since pipe writes there are only atomic up to 512 bytes (PIPE_BUF), so serialized frames larger than that can be split with a grandchild's write interleaved in the gap.Verified the mechanism with a repro: a test spawning a child that writes
FF 0F-prefixed bytes to inherited stdout undernode --testdeterministically destroys the run. Matches upstream reports like nodejs/node#64061.Fix
deno-testfunnels every test file through a single runner file, so process isolation buys nothing here.--test-isolation=none(stable since Node 23; CI uses 24.x) runs the tests in the main process — no serialization pipe exists, and inherited stdio goes to the real terminal. Injected viaNODE_OPTIONSsince thedeno-testbin doesn't forward extra flags.Full suite passes locally with the flag, and the poison-byte repro passes cleanly too. Longer term,
deno-testitself could pass--test-isolation=nonesince its single-runner design makes isolation pure overhead.