diff --git a/.changeset/olive-spies-listen.md b/.changeset/olive-spies-listen.md new file mode 100644 index 0000000000..8e09f0a60b --- /dev/null +++ b/.changeset/olive-spies-listen.md @@ -0,0 +1,7 @@ +--- +"@pnpm/deps.inspection.list": patch +"@pnpm/workspace.project-manifest-reader": patch +"pnpm": patch +--- + +Limit concurrent project manifest reads while listing large workspaces to avoid `EMFILE` errors. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0582ecde11..96a6619227 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9638,6 +9638,9 @@ importers: json5: specifier: 'catalog:' version: 2.2.3 + p-limit: + specifier: 'catalog:' + version: 7.3.0 parse-json: specifier: 'catalog:' version: 8.3.0 diff --git a/workspace/project-manifest-reader/package.json b/workspace/project-manifest-reader/package.json index f13473d859..e6e016e40b 100644 --- a/workspace/project-manifest-reader/package.json +++ b/workspace/project-manifest-reader/package.json @@ -41,6 +41,7 @@ "fast-deep-equal": "catalog:", "is-windows": "catalog:", "json5": "catalog:", + "p-limit": "catalog:", "parse-json": "catalog:", "read-yaml-file": "catalog:", "strip-bom": "catalog:" diff --git a/workspace/project-manifest-reader/src/index.ts b/workspace/project-manifest-reader/src/index.ts index 1e10a039ec..13daed335f 100644 --- a/workspace/project-manifest-reader/src/index.ts +++ b/workspace/project-manifest-reader/src/index.ts @@ -9,6 +9,7 @@ import { writeProjectManifest } from '@pnpm/workspace.project-manifest-writer' import detectIndent from 'detect-indent' import equal from 'fast-deep-equal' import isWindows from 'is-windows' +import pLimit from 'p-limit' import { readYamlFile } from 'read-yaml-file' import { @@ -18,15 +19,19 @@ import { export type WriteProjectManifest = (manifest: ProjectManifest, force?: boolean) => Promise +const limitProjectManifestReads = pLimit(4) + export async function safeReadProjectManifestOnly (projectDir: string): Promise { - try { - return await readProjectManifestOnly(projectDir) - } catch (err: any) { // eslint-disable-line - if ((err as NodeJS.ErrnoException).code === 'ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND') { - return null + return limitProjectManifestReads(async () => { + try { + return await readProjectManifestOnly(projectDir) + } catch (err: any) { // eslint-disable-line + if ((err as NodeJS.ErrnoException).code === 'ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND') { + return null + } + throw err } - throw err - } + }) } export async function readProjectManifest (projectDir: string): Promise<{