From 5b402ea22ba3e417e514ffa96a73ae0c03a43f02 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sat, 13 Jun 2026 22:21:25 +0200 Subject: [PATCH] test(deps-installer): isolate the heavy deepRecursive test in its own process (#12388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test/install/deepRecursive.ts resolves @teambit/bit's enormous circular and peer-dependency graph. Measured in a CI-faithful container (Linux, Node 22.13.0, amd64, default ~4 GB heap) it peaks at ~3.6 GB — it fits the default heap on its own, but not with the memory the other deps-installer test files leave behind in the same jest process (the --experimental-vm-modules module registry is not reclaimed between files). That overflow is the "FATAL ERROR: Reached heap limit" the CI suite hit. Run deepRecursive in a dedicated jest process (.test:heavy) so it gets the whole default heap to itself, and run the rest (.test:rest) in a separate process with it excluded via a negative-lookahead path pattern. The two runs cover every test file exactly once. This makes the earlier OOM workarounds unnecessary, so they are reverted: - the 5-way sharding of the suite (deepRecursive was the sole culprit; the remaining files are a subset of what historically ran in one process), and - the workerIdleMemoryLimit in the with-registry jest preset. No global heap bump: every run stays within Node's default ~4 GB, matching the budget pnpm has in production. --- .meta-updater/src/index.ts | 16 +++++++++++++--- .../jest-config/with-registry/jest-preset.js | 9 --------- installing/deps-installer/package.json | 5 +++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.meta-updater/src/index.ts b/.meta-updater/src/index.ts index 078c2495f8..fd088df33f 100644 --- a/.meta-updater/src/index.ts +++ b/.meta-updater/src/index.ts @@ -333,7 +333,6 @@ const yamlTextFormat = createFormat({ }, }) -const depsInstallerTestShardCount = 5 const registryMockPortForCore = 7769 async function updateManifest (workspaceDir: string, manifest: ProjectManifest, dir: string, nextTag: string): Promise { @@ -369,8 +368,19 @@ async function updateManifest (workspaceDir: string, manifest: ProjectManifest, if (manifest.name === '@pnpm/installing.deps-installer') { // @pnpm/installing.deps-installer tests currently works only with port 7769 due to the usage of // the next package: pkg-with-tarball-dep-from-registry - scripts['.test'] = Array.from({ length: depsInstallerTestShardCount }, (_, index) => `pn .test:shard --shard=${index + 1}/${depsInstallerTestShardCount}`).join(' && ') - scripts['.test:shard'] = `cross-env PNPM_REGISTRY_MOCK_PORT=${registryMockPortForCore} NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" jest` + // + // deepRecursive resolves @teambit/bit's enormous circular/peer graph and + // needs ~3.6 GB on its own — enough to fit Node's default ~4 GB heap, but + // not with the memory the other test files leave behind in the same + // process (Jest's `--experimental-vm-modules` registry isn't reclaimed + // between files). Run it in a dedicated jest process (`.test:heavy`) so it + // gets the whole heap to itself, and run the rest (`.test:rest`) in a + // separate process with it excluded. + const heavyTestPath = 'test/install/deepRecursive.ts' + const testEnv = `cross-env PNPM_REGISTRY_MOCK_PORT=${registryMockPortForCore} NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169"` + scripts['.test'] = 'pn .test:heavy && pn .test:rest' + scripts['.test:heavy'] = `${testEnv} jest ${heavyTestPath}` + scripts['.test:rest'] = `${testEnv} jest "^(?!.*deepRecursive)"` } else { scripts['.test'] = 'cross-env NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" jest' } diff --git a/__utils__/jest-config/with-registry/jest-preset.js b/__utils__/jest-config/with-registry/jest-preset.js index 07c677789a..e08e981fc5 100644 --- a/__utils__/jest-config/with-registry/jest-preset.js +++ b/__utils__/jest-config/with-registry/jest-preset.js @@ -7,15 +7,6 @@ export default { // Unfortunately, this means that if two such tests will run at the same time, // they may break each other. maxWorkers: 1, - // Recycle the test worker once its heap crosses this limit. Under - // `--experimental-vm-modules` Jest's VM module registry is never released - // between test files, so a long-running process climbs to Node's ~4 GB - // old-space ceiling and dies with an out-of-memory FATAL ERROR. Setting a - // limit is also what keeps `maxWorkers: 1` from collapsing to in-band - // execution (see `shouldRunInBand`): a recyclable worker is spawned instead, - // still serial, so the leaked memory is reclaimed between files without - // reintroducing the dist-tag races `maxWorkers: 1` prevents. - workerIdleMemoryLimit: '1500MB', // Force Jest to exit after globalTeardown completes. The Verdaccio server // and lifecycle child-processes spawned during tests may leave ref'd handles // that prevent the process from exiting on its own. diff --git a/installing/deps-installer/package.json b/installing/deps-installer/package.json index 27632c184b..33fcf81d7c 100644 --- a/installing/deps-installer/package.json +++ b/installing/deps-installer/package.json @@ -53,8 +53,9 @@ "test": "pn compile && pn .test", "prepublishOnly": "tsgo --build", "compile": "tsgo --build && pn lint --fix", - ".test": "pn .test:shard --shard=1/5 && pn .test:shard --shard=2/5 && pn .test:shard --shard=3/5 && pn .test:shard --shard=4/5 && pn .test:shard --shard=5/5", - ".test:shard": "cross-env PNPM_REGISTRY_MOCK_PORT=7769 NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest" + ".test": "pn .test:heavy && pn .test:rest", + ".test:heavy": "cross-env PNPM_REGISTRY_MOCK_PORT=7769 NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest test/install/deepRecursive.ts", + ".test:rest": "cross-env PNPM_REGISTRY_MOCK_PORT=7769 NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest \"^(?!.*deepRecursive)\"" }, "dependencies": { "@inquirer/prompts": "catalog:",