Skip to content

Commit 1c65f5d

Browse files
A.R.claude
andcommitted
chore(ci): stop windows-latest/Node-24 vitest worker OOM kills
Recent main runs failed only on the windows-latest + Node 24 matrix cell: ~5 forks-pool workers died with "Worker exited unexpectedly" (an OS reap, no JS error — classic OOM), which (a) surfaced as unhandled errors and (b) dropped packages/mcp-server/src/profiles.js function coverage from 87.5% to 83.33%, under its 85% per-file floor. It reproduced on neither ubuntu nor windows/Node-22, nor locally (test:coverage passes clean: 1172 tests, profiles.js funcs 87.5%, zero crashes). Root cause: NODE_OPTIONS=--max-old-space-size=4096 was set at the workflow env level (for the tsup/tsc build) and inherited by the vitest test step, so every forked worker was allowed a 4GB heap; several parallel workers ×4GB on the Node-24 Windows runner caused OOM worker kills. Fix (CI-only, no package change): - Move NODE_OPTIONS=--max-old-space-size=4096 off the global env onto the build and typecheck steps only; the multi-worker test step now runs with Node's default per-worker heap. - Cap the vitest forks pool to maxForks=2 in CI (poolOptions.forks) to bound peak concurrent memory. Local runs keep default parallelism. Verified the config parses and tests pass under CI=1 locally (maxForks path); the OOM kills only repro on the hosted runner, so the real confirmation is the next CI run on this commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent adc5986 commit 1c65f5d

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

.github/workflows/ci.yml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ on:
77

88
env:
99
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
10-
# tsup's --dts worker hits Node's default ~2GB heap during the mcp-server
11-
# build (70+ entry points + DTS emission). Lift the cap to 4GB; both
12-
# ubuntu-latest and windows-latest runners have ~7GB RAM available.
13-
NODE_OPTIONS: "--max-old-space-size=4096"
10+
# NOTE: NODE_OPTIONS=--max-old-space-size is deliberately NOT set at the
11+
# workflow level. The vitest `forks` pool spawns several worker child
12+
# processes that inherit this env; a 4GB-per-worker cap let the
13+
# windows-latest + Node 24 runner OOM-kill workers ("Worker exited
14+
# unexpectedly"), which failed the run AND dropped per-file coverage below
15+
# threshold (issue: Windows CI flakiness). The heap bump is scoped to the
16+
# build/typecheck steps only — see below; the test step runs with Node's
17+
# default per-worker heap.
1418
# Opt into Node 24 for GitHub-shipped JS actions (checkout, setup-node, …)
1519
# ahead of the June 2nd 2026 default. Silences the deprecation warning and
1620
# ensures we're on the runtime GitHub is migrating to.
@@ -47,8 +51,16 @@ jobs:
4751
elif [ "$RUNNER_OS" = "macOS" ]; then
4852
npm install --no-save --workspaces=false @tailwindcss/oxide-darwin-arm64 @tailwindcss/oxide-darwin-x64
4953
fi
54+
# tsup's --dts worker + tsc across 4 packages can exceed Node's default
55+
# heap on the mcp-server build (70+ entry points + DTS emission). Lift the
56+
# cap to 4GB for these single-process steps ONLY — never the multi-worker
57+
# test step (see env note above).
5058
- run: npm run build
59+
env:
60+
NODE_OPTIONS: "--max-old-space-size=4096"
5161
- run: npm run typecheck
62+
env:
63+
NODE_OPTIONS: "--max-old-space-size=4096"
5264
- name: Test with coverage
5365
run: |
5466
mkdir -p .test-artifacts

vitest.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ export default defineConfig({
2525
: []),
2626
],
2727
environment: "node",
28+
// CI (notably windows-latest + Node 24) intermittently OOM-killed
29+
// forks-pool workers ("Worker exited unexpectedly"), which both failed the
30+
// run and dropped per-file coverage below threshold. Cap concurrent forks
31+
// in CI to bound peak memory (combined with not inheriting a 4GB-per-worker
32+
// heap — see .github/workflows/ci.yml). Local runs keep vitest's default
33+
// parallelism for speed.
34+
pool: "forks",
35+
...(process.env.CI
36+
? { poolOptions: { forks: { maxForks: 2, minForks: 1 } } }
37+
: {}),
2838
coverage: {
2939
provider: "v8",
3040
reporter: ["text", "html", "json-summary"],

0 commit comments

Comments
 (0)