发布

  • fix(repo): resolve FreeBSD build OOM and disk exhaustion (#35309)

    frostbyte_neo 发布于 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:

    1. Jest plugin OOM: PR #35231 changed createNodes to load all jest
      configs upfront in a sequential for loop before hash computation. Each
      loadConfigFile registers a ts-node transpiler via registerTsProject
      (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
      transpilerCleanup is 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 under NX_PREFER_TS_NODE=true (set
      for the FreeBSD build), 96 ts-node services stack and OOM at V8's ~2GB
      heap limit.

    2. Core dump fills disk: When the jest plugin OOMs, FreeBSD writes a
      2.3GB node.core file to the workspace root, filling the remaining 4GB
      of free disk space before cargo can run.

    Failing runs

    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 for loop to
      Promise.all(validConfigFiles.map(async ...)). Keeps all
      registerTsProject registrations alive concurrently so refCount goes
      0→1→2→…→N→N-1→…→0 and only one ts-node service is ever created.
    • Preserves #35231's hash correctness: preset path and tsconfig extends
      chain remain inputs to calculateHashesForCreateNodes; 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.12 so the
      FreeBSD build (which uses the published package, not source) gets the
      fix immediately. Generated via pnpm patch from the built source output
      — installed plugin.js is byte-identical to
      dist/packages/jest/src/plugins/plugin.js.

    Workflow hardening (.github/workflows/publish.yml):

    • ulimit -c 0 to 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 reset before 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 MB at 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.cache constant at 599 entries. No accumulation.
    • Real nx show projects end-to-end: 600 MB RSS, 5 s.

    Follow-up (separate PR)

    packages/nx/src/plugins/js/utils/register.js has 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 gating registered.delete
    on whether the transpiler is actually disposable, analogous to the
    existing isTsEsmLoaderRegistered flag. 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

    下载附件