Repository navigation
chore(wb): drop --no-isolate from wb test once a stable Bun fixes the spawnSync hang #1425
Description
Background and goal
wb test runs unit tests with bun test --parallel --no-isolate (#1421). --no-isolate works around a Bun 1.4.2 bug (oven-sh/bun#34069; unmerged fix oven-sh/bun#40078). With the default per-file isolation that --parallel implies, the stdout/stderr writers of a discarded per-file global can be garbage-collected inside a later spawnSync. That spawnSync and later ones in the same worker then spin without noticing the child's exit, the child stays a zombie, and the test hangs until its timeout (killed 1 dangling process). In CI this made normally sub-second tests (for example deployRailway.test.ts) time out in 3 of 7 Test runs on main.
--no-isolate makes the files of one worker share a global, a module registry, and process.env. Per-file isolation is the safer contract for every repository using wb, so it should be restored once the Bun bug is fixed in a stable release.
Behavior
Once a stable Bun release contains the fix from oven-sh/bun#40078 (or another fix that oven-sh/bun#34069 records as resolving it) and mise.toml pins it, testUnit in packages/wb/src/scripts/execution/baseScripts.ts passes --parallel without --no-isolate, and the comment there that references the Bun issue is removed.
Acceptance criteria
- The Bun version pinned in
mise.tomlcontains the fix for Bug: spawnSync never returns: child exit lost (child stays zombie), wait loop busy-spins at 100% CPU re-registering a finished pipe reader (macOS ARM64) oven-sh/bun#34069 (its release notes or the merged fix PR say so). The reproduction alone does not establish this: from Bun mainb52d51348(a WebKit bump, Bump WebKit to 000c48997255 oven-sh/bun#43022) on, the reproduction no longer wedges even without the fix, while spawnSync: release polls and keep-alives on the loop they counted on oven-sh/bun#40078 reports its own test still wedging on that commit. - Given the Bun version pinned in
mise.toml, when the reproduction below runs with per-file isolation (no--no-isolate), then 0 of 10 runs wedge, matching the--no-isolateresult. - Several Test workflow runs (for example 8
workflow_dispatchruns) of the change pass without a timeout that showskilled 1 dangling process. docs/expected-repository-rules.mdagain describes each unit test file as running in a fresh global, if the rule about sharing state is relaxed.
Scope and non-goals
In scope: the wb test flag, its comment, and the matching rule text in docs/expected-repository-rules.md. Not in scope: the environment-restoring test changes and the once-per-run buildWb build from #1421. They stay correct under isolation, so keep them.
Verification
Reproduction (Linux, which is what CI uses):
-
Run Docker with 4 CPUs on the candidate Bun version (for example the
oven/bun:<version>image or Ubuntu 24.04 with Bun installed by mise). -
Create 12 identical test files
test/s1.test.mjs…test/s12.test.mjswith the following content:import { execFileSync } from 'node:child_process'; import { test } from 'bun:test'; const BYTES = 200000; const child = (i) => execFileSync('/bin/sh', ['-c', `yes abcdefghij | head -c ${BYTES}; echo e${i} >&2`], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 }); await Promise.resolve(); for (let i = 0; i < 150; i += 1) { if (i % 4 === 0) await new Promise((r) => setTimeout(r, 0)); else await Promise.resolve(); if (child(i).length < BYTES) throw new Error('short read'); if (i % 50 === 0) process.stdout.write(`round ${i}\n`); } test('loaded', () => {});
-
Run each mode 10 times with stdout on a pipe and a 60 s cap, counting exits with code 124 as wedged:
timeout 60 bun test ./test/ --parallel=4 | catandtimeout 60 bun test ./test/ --parallel=4 --no-isolate | cat.
Results on Bun 1.4.2 (aarch64 container, 4 CPUs):
--parallel=4: 7/10 and 9/10 runs wedged. A wedged worker stays in state R with itsshchild a zombie.--parallel=4 --no-isolate: 0/10 wedged.--parallel=4 --preloadof a file callingBun.gc(true): 10/10 wedged, so that is not an alternative.
A fixed Bun must show 0/10 without --no-isolate; this is necessary but not sufficient (see Acceptance criteria). The same reproduction is published at https://github.com/exKAZUu/bun-spawnsync-hang-repro with per-build results in oven-sh/bun#34069 (comment).
Activity