mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-27 09:25:24 -04:00
test(deps-installer): isolate the heavy deepRecursive test in its own process (#12388)
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.
This commit is contained in:
@@ -333,7 +333,6 @@ const yamlTextFormat = createFormat<string>({
|
||||
},
|
||||
})
|
||||
|
||||
const depsInstallerTestShardCount = 5
|
||||
const registryMockPortForCore = 7769
|
||||
|
||||
async function updateManifest (workspaceDir: string, manifest: ProjectManifest, dir: string, nextTag: string): Promise<ProjectManifest> {
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:",
|
||||
|
||||
Reference in New Issue
Block a user