Repository navigation
fix(wbfy): stop calling Bun's spawnSync from wbfy and shared-lib-node's getGlobIgnore #1433
Description
Background and goal
Bun 1.4.2's synchronous spawns (spawnSync, execSync, execFileSync, Bun.spawnSync) can miss a child's exit and spin until something kills the child (oven-sh/bun#34069; fix pending in oven-sh/bun#40078). The cause is not specific to bun test. If the GC finalizes any object that owns a poll on the main event loop (a FileSink, a Subprocess, a socket) while a spawnSync call is waiting, the private loop of every later spawnSync call in that process loses count. #1432 moved the unit tests off synchronous spawns. That covers the wb CLI, which runs under Node, but not the code below, which still runs under Bun:
wbfyruns under Bun (bin/wbfy.jsis#!/usr/bin/env bun) and makes all of its child-process calls synchronously (src/utils/spawnUtil.ts,fnoxToml.ts,gitattributes.ts,globalReleaseAgeGate.ts,githubUtil.ts,version.ts), next to asyncfetchcalls and generators running concurrently. Inwbfy's own unit suite these calls run in-process, inside the test workers: 125 calls taking 23 s per run, most of themnpm show(34 s across 40 calls in an earlier measurement) andmise latestlookups.getGlobIgnoreof@willbooster/shared-lib-node(fix(wbfy,wb): ignore gitignored files when detecting repository contents #1431) runsgit rev-parseandgit ls-filesthroughspawnSync/execFileSync.wbfycalls it frompackageConfig.ts,packageJson.ts,typos.ts, andchakraToaster.ts(about 120 calls perwbfyunit run).wb slidev-checkcalls it as well.
A hang has not been observed in a real wbfy run so far. In a test worker, it would show up as a test killed at its timeout with killed 1 dangling process. In a wbfy run, the process would spin at 100% CPU with no timeout to end it.
Behavior
wbfy and getGlobIgnore launch child processes asynchronously (e.g., spawnAsync of @willbooster/shared-lib-node), so no synchronous spawn runs in a Bun process.
Acceptance criteria
- A preload that counts the synchronous spawn APIs called inside test workers counts 0 calls from
wbfy's andgetGlobIgnore's code duringbun wb testinpackages/wbfy. wbfyproduces the same files as before on a sample repository, with and without workspaces.
Scope and non-goals
In scope: packages/wbfy/src and packages/shared-lib-node/src/glob.ts with their callers. Not in scope: readEnvironmentVariables and treeKill of @willbooster/shared-lib-node, whose callers depend on them being synchronous.
Design constraints
The conversion lets concurrently running generators interleave at every spawn. In src/index.ts, generators pushed to promises (e.g. generateTsconfig, generateOxlintConfig) run while the next package's generatePackageJson runs bun add and sort-package-json, which rewrite package.json. Check every such pair for reads of files another generator rewrites, or run those steps sequentially. Before this change, a synchronous spawn kept them from interleaving.
Verification
The probe count above, the existing wbfy unit tests, and a wbfy run on a WillBooster repository before and after with an identical diff.
Activity