From 3b5d1713e1da6eb496b6318ce0473436f2991b3b Mon Sep 17 00:00:00 2001 From: Omar Brikaa Date: Mon, 2 May 2022 19:23:15 +0200 Subject: [PATCH 1/2] Destroy stdin if not destroyed --- api/src/job.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/src/job.js b/api/src/job.js index 9b057e6..d690741 100644 --- a/api/src/job.js +++ b/api/src/job.js @@ -195,6 +195,10 @@ class Job { clear_timeout(kill_timeout); proc.stderr.destroy(); + if (!proc.stdin.destroyed) { + proc.stdin.end(); + proc.stdin.destroy(); + } proc.stdout.destroy(); this.cleanup_processes(); From e17783297cb0832b639ceb2c156c9acf6216945a Mon Sep 17 00:00:00 2001 From: Omar Brikaa Date: Mon, 2 May 2022 19:39:11 +0200 Subject: [PATCH 2/2] Clear hanging timeouts and parent processes writables --- api/src/job.js | 51 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/api/src/job.js b/api/src/job.js index d690741..7b4622d 100644 --- a/api/src/job.js +++ b/api/src/job.js @@ -28,6 +28,9 @@ setInterval(() => { }, 10); class Job { + #active_timeouts; + #active_parent_processes; + constructor({ runtime, files, args, stdin, timeouts, memory_limits }) { this.uuid = uuidv4(); @@ -45,6 +48,9 @@ class Job { this.args = args; this.stdin = stdin; + this.#active_timeouts = []; + this.#active_parent_processes = []; + this.timeouts = timeouts; this.memory_limits = memory_limits; @@ -109,6 +115,28 @@ class Job { this.logger.debug('Primed job'); } + exit_cleanup() { + for (const timeout of this.#active_timeouts) { + clear_timeout(timeout); + } + this.#active_timeouts = []; + this.logger.debug('Cleared the active timeouts'); + + for (const proc of this.#active_parent_processes) { + proc.stderr.destroy(); + if (!proc.stdin.destroyed) { + proc.stdin.end(); + proc.stdin.destroy(); + } + proc.stdout.destroy(); + } + this.#active_parent_processes = []; + this.logger.debug('Destroyed parent processes writables'); + + this.cleanup_processes(); + this.logger.debug(`Finished exit cleanup`); + } + async safe_call(file, args, timeout, memory_limit, eventBus = null) { return new Promise((resolve, reject) => { const nonetwork = config.disable_networking ? ['nosocket'] : []; @@ -145,6 +173,8 @@ class Job { detached: true, //give this process its own process group }); + this.#active_parent_processes.push(proc); + if (eventBus === null) { proc.stdin.write(this.stdin); proc.stdin.end(); @@ -166,6 +196,7 @@ class Job { process.kill(proc.pid, 'SIGKILL'); }, timeout)) || null; + this.#active_timeouts.push(kill_timeout); proc.stderr.on('data', async data => { if (eventBus !== null) { @@ -191,28 +222,14 @@ class Job { } }); - const exit_cleanup = () => { - clear_timeout(kill_timeout); - - proc.stderr.destroy(); - if (!proc.stdin.destroyed) { - proc.stdin.end(); - proc.stdin.destroy(); - } - proc.stdout.destroy(); - - this.cleanup_processes(); - this.logger.debug(`Finished exit cleanup`); - }; - proc.on('exit', (code, signal) => { - exit_cleanup(); + this.exit_cleanup(); resolve({ stdout, stderr, code, signal, output }); }); proc.on('error', err => { - exit_cleanup(); + this.exit_cleanup(); reject({ error: err, stdout, stderr, output }); }); @@ -422,7 +439,7 @@ class Job { async cleanup() { this.logger.info(`Cleaning up job`); - this.cleanup_processes(); // Run process janitor, just incase there are any residual processes somehow + this.exit_cleanup(); // Run process janitor, just incase there are any residual processes somehow await this.cleanup_filesystem(); remaining_job_spaces++;