From 81386e91c93439fbd2cdf9e14bfbfc8e42f39297 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 6 Apr 2021 16:24:35 +0200 Subject: [PATCH] fix(node-runtime-worker-thread): reset require cache after interrupt MONGOSH-666 Clear the require cache after an interrupt occurred. This is currently making our test suite flaky, because the interrupt can also occur during the babel transformation of the async rewriter (either one), which lazy-loads other modules from babel packages. If those are loaded incompletely during the first `require()` call, they are still left in the cache (as `interruptor` fully stops execution and also skips catch/finally handlers which would remove them from the cache). Subsequent loads receive incomplete module exports in that case. One alternative would be to try to only wrap the actual `evaluate` call in the `runInterruptible()` wrapper. This seems a bit cleaner, but would also require changing the `Runtime` interface a bit in a way that cannot be proxied across the child process/Worker barrier. --- .../node-runtime-worker-thread/src/worker-runtime.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/node-runtime-worker-thread/src/worker-runtime.ts b/packages/node-runtime-worker-thread/src/worker-runtime.ts index f4c124b418..555690d448 100644 --- a/packages/node-runtime-worker-thread/src/worker-runtime.ts +++ b/packages/node-runtime-worker-thread/src/worker-runtime.ts @@ -97,6 +97,7 @@ const workerRuntime: WorkerRuntime = { let interrupted = true; let evaluationPromise: void | Promise; + const previousRequireCache = Object.keys(require.cache); try { evaluationPromise = runInterruptible((handle) => { @@ -109,6 +110,17 @@ const workerRuntime: WorkerRuntime = { }); } finally { evaluationListener.onRunInterruptible(null); + + if (interrupted) { + // If we were interrupted, we can't know which newly require()ed modules + // have successfully been loaded, so we restore everything to its + // previous state. + for (const key of Object.keys(require.cache)) { + if (!previousRequireCache.includes(key)) { + delete require.cache[key]; + } + } + } } let result: void | RuntimeEvaluationResult | UNLOCKED;