From 5405fe459055cf7a3f2c4213dea698797e460ca0 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 13 Dec 2024 08:42:28 -0500 Subject: [PATCH] fix(cli-repl): account for possibility of `process.exit()` throwing under coverage MONGOSH-1943 (#2298) When running under `nyc` for coverage generation, the process's `process.exit()` internals get monkey-patched to give `nyc` the opportunity to write coverage data as part of that operation. However, for processes running under changed working directories, `nyc` may try to write to an incorrect directory, making the `fs.writeFile()` call fail with an exception, and so `process.exit()` may not actually stop the process. This commit adds a `process.abort()` call to make that accounts for this situation, as well as improved debugging for it. --- packages/cli-repl/src/run.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/cli-repl/src/run.ts b/packages/cli-repl/src/run.ts index cd9d32aca..fac73df76 100644 --- a/packages/cli-repl/src/run.ts +++ b/packages/cli-repl/src/run.ts @@ -232,9 +232,7 @@ async function main() { process.env.TEST_USE_STDOUT_FOR_PASSWORD || process.stdout.isTTY ? process.stdout : process.stderr, - // Node.js 20.0.0 made p.exit(undefined) behave as p.exit(0) rather than p.exit() - onExit: (code?: number | undefined) => - code === undefined ? process.exit() : process.exit(code), + onExit, shellHomePaths: shellHomePaths, globalConfigPaths: globalConfigPaths, }); @@ -341,3 +339,25 @@ function suppressExperimentalWarnings() { }; } } + +function onExit(code?: number): never { + // Node.js 20.0.0 made p.exit(undefined) behave as p.exit(0) rather than p.exit(): (code?: number | undefined): never => { + try { + try { + if (code === undefined) process.exit(); + else process.exit(code); + } finally { + if (code === undefined) process.exit(); + else process.exit(code); + } + } catch (err) { + process.stderr.write(String(err) + '\n'); + } finally { + // Should never be reachable anyway, but nyc monkey-patches process.exit() + // internals so that it can always write coverage files as part of the application + // shutdown, and that can throw an exception if the filesystem call to write + // the coverage file fails. + process.stderr.write('process.exit() returned -- aborting\n'); + process.abort(); + } +}