From ec160939f7a8ea6ec9a912109555a987bb2dc318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 16 Feb 2024 11:07:31 +0100 Subject: [PATCH] add cmd limiter to the cli MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/nasty-suns-speak.md | 5 +++ packages/repo-tools/src/commands/util.ts | 54 +++++++++++++++--------- 2 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 .changeset/nasty-suns-speak.md diff --git a/.changeset/nasty-suns-speak.md b/.changeset/nasty-suns-speak.md new file mode 100644 index 0000000000..2c5fff25a1 --- /dev/null +++ b/.changeset/nasty-suns-speak.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Add an internal limiter on concurrency when launching processes diff --git a/packages/repo-tools/src/commands/util.ts b/packages/repo-tools/src/commands/util.ts index 933945bc5c..e28aae6267 100644 --- a/packages/repo-tools/src/commands/util.ts +++ b/packages/repo-tools/src/commands/util.ts @@ -13,29 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { execFile } from 'child_process'; +import os from 'os'; +import pLimit from 'p-limit'; + +// Some commands launch full node processes doing heavy work, which at high +// concurrency levels risk exhausting system resources. Placing the limiter here +// at the root level ensures that the concurrency boundary applies globally, not +// just per-runner. +const limiter = pLimit(os.cpus().length); export function createBinRunner(cwd: string, path: string) { return async (...command: string[]) => - new Promise((resolve, reject) => { - execFile( - 'node', - [path, ...command], - { - cwd, - shell: true, - timeout: 60000, - maxBuffer: 1024 * 1024, - }, - (err, stdout, stderr) => { - if (err) { - reject(new Error(`${err.message}\n${stderr}`)); - } else if (stderr) { - reject(new Error(`Command printed error output: ${stderr}`)); - } else { - resolve(stdout); - } - }, - ); - }); + limiter( + () => + new Promise((resolve, reject) => { + execFile( + 'node', + [path, ...command], + { + cwd, + shell: true, + timeout: 60000, + maxBuffer: 1024 * 1024, + }, + (err, stdout, stderr) => { + if (err) { + reject(new Error(`${err.message}\n${stderr}`)); + } else if (stderr) { + reject(new Error(`Command printed error output: ${stderr}`)); + } else { + resolve(stdout); + } + }, + ); + }), + ); }