-
fix(repo): resolve FreeBSD build OOM and disk exhaustion (#35309)
发布于
2026-04-16 21:55:42 +00:00 Current Behavior
The FreeBSD native build in the publish workflow fails with "filesystem
full" or OOM. Two issues:-
Jest plugin OOM: PR #35231 changed
createNodesto load all jest
configs upfront in a sequentialforloop before hash computation. Each
loadConfigFileregisters a ts-node transpiler viaregisterTsProject
(packages/nx/src/plugins/js/utils/register.js), whose dedup is
refcounted. Serial register/unregister cycles drive refCount to 0
between iterations and delete the Map entry — but ts-node's
transpilerCleanupis a no-op, so the service stays alive in
require.extensions. The next iteration creates a fresh ts-node
service. Across 96 TS jest configs underNX_PREFER_TS_NODE=true(set
for the FreeBSD build), 96 ts-node services stack and OOM at V8's ~2GB
heap limit. -
Core dump fills disk: When the jest plugin OOMs, FreeBSD writes a
2.3GBnode.corefile to the workspace root, filling the remaining 4GB
of free disk space before cargo can run.
Failing runs
- beta.13 publish (Apr
15)
—filesystem fullduring project graph, cargo never ran - Canary after beta.12 (Apr
10)
— jest plugin OOM at 2GB heap,node.corefilled disk - Diagnostics
run
— confirmed 2.3GBnode.corefile in workspace root
Passing run (with pnpm patch)
- Fix validation run (Apr
16)
— jest plugin no longer OOMs, cargo compiles successfully (validated an
earlier lazy-load form of the patch; the current form uses parallel load
but is equivalent for FreeBSD's resource envelope)
Expected Behavior
The FreeBSD build completes successfully. The jest plugin loads configs
in parallel so the ts-node transpiler dedup holds across all
registrations and only one service is created.Changes
Jest plugin memory fix (
packages/jest/src/plugins/plugin.ts):- Convert the upfront config-loading
forloop to
Promise.all(validConfigFiles.map(async ...)). Keeps all
registerTsProjectregistrations alive concurrently so refCount goes
0→1→2→…→N→N-1→…→0and only one ts-node service is ever created. - Preserves #35231's hash correctness: preset path and tsconfig extends
chain remain inputs tocalculateHashesForCreateNodes;needsDtsInputs
is still derived from the real jest config + ts-jest transform
inspection.
pnpm patch (
patches/@nx__jest@22.7.0-beta.12.patch):- Same fix applied to the installed
@nx/jest@22.7.0-beta.12so the
FreeBSD build (which uses the published package, not source) gets the
fix immediately. Generated viapnpm patchfrom the built source output
— installedplugin.jsis byte-identical to
dist/packages/jest/src/plugins/plugin.js.
Workflow hardening (
.github/workflows/publish.yml):ulimit -c 0to disable core dumps (prevents 2.3GB files from filling
disk)NODE_OPTIONS='--max-old-space-size=4096'as a safety net- Disk usage diagnostics on build failure for future debugging
Local verification
Cold cache (
npx nx resetbefore each run),NX_PREFER_TS_NODE=true NX_CACHE_PROJECT_GRAPH=false NX_DAEMON=false, 96 TS jest configs:- Pre-fix (serial for-loop): per-iteration heap grows
40 → 60 → 160 → 756 MBat iter 1/10/20/30, then OOM at iter ~33 with
--max-old-space-size=4096. - Post-fix (parallel): heap flat at 272 MB from load 1 through
96.require.cacheconstant at 599 entries. No accumulation. - Real
nx show projectsend-to-end: 600 MB RSS, 5 s.
Follow-up (separate PR)
packages/nx/src/plugins/js/utils/register.jshas a latent leak: when
the transpiler has no real cleanup (ts-node always, swc sometimes),
registered.delete(registrationKey)on refCount==0 allows the next
registration with the same key to stack a fresh service. Any Nx plugin
that loads configs serially hits this. Worth gatingregistered.delete
on whether the transpiler is actually disposable, analogous to the
existingisTsEsmLoaderRegisteredflag. Not in scope for this PR.Related Issue(s)
Fixes the FreeBSD build failure in the publish workflow.
Co-authored-by: Leosvel Pérez Espinosa leosvel.perez.espinosa@gmail.com
下载附件
-