Merge pull request #632 from ssahai/bugfix/catch_error

Handle process kills gracefully
This commit is contained in:
Thomas Hobson 2023-11-01 14:06:28 +13:00 committed by GitHub
commit a7fa1b47fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 52 additions and 25 deletions

View File

@ -146,7 +146,7 @@ class Job {
'--nofile=' + this.runtime.max_open_files, '--nofile=' + this.runtime.max_open_files,
'--fsize=' + this.runtime.max_file_size, '--fsize=' + this.runtime.max_file_size,
]; ];
const timeout_call = [ const timeout_call = [
'timeout', 'timeout',
'-s', '-s',
@ -158,7 +158,7 @@ class Job {
prlimit.push('--as=' + memory_limit); prlimit.push('--as=' + memory_limit);
} }
const proc_call = [ const proc_call = [
'nice', 'nice',
...timeout_call, ...timeout_call,
...prlimit, ...prlimit,
@ -204,7 +204,16 @@ class Job {
(timeout >= 0 && (timeout >= 0 &&
set_timeout(async _ => { set_timeout(async _ => {
this.logger.info(`Timeout exceeded timeout=${timeout}`); this.logger.info(`Timeout exceeded timeout=${timeout}`);
process.kill(proc.pid, 'SIGKILL'); try {
process.kill(proc.pid, 'SIGKILL');
}
catch (e) {
// Could already be dead and just needs to be waited on
this.logger.debug(
`Got error while SIGKILLing process ${proc}:`,
e
);
}
}, timeout)) || }, timeout)) ||
null; null;
this.#active_timeouts.push(kill_timeout); this.#active_timeouts.push(kill_timeout);
@ -214,7 +223,16 @@ class Job {
event_bus.emit('stderr', data); event_bus.emit('stderr', data);
} else if (stderr.length > this.runtime.output_max_size) { } else if (stderr.length > this.runtime.output_max_size) {
this.logger.info(`stderr length exceeded`); this.logger.info(`stderr length exceeded`);
process.kill(proc.pid, 'SIGKILL'); try {
process.kill(proc.pid, 'SIGKILL');
}
catch (e) {
// Could already be dead and just needs to be waited on
this.logger.debug(
`Got error while SIGKILLing process ${proc}:`,
e
);
}
} else { } else {
stderr += data; stderr += data;
output += data; output += data;
@ -226,7 +244,16 @@ class Job {
event_bus.emit('stdout', data); event_bus.emit('stdout', data);
} else if (stdout.length > this.runtime.output_max_size) { } else if (stdout.length > this.runtime.output_max_size) {
this.logger.info(`stdout length exceeded`); this.logger.info(`stdout length exceeded`);
process.kill(proc.pid, 'SIGKILL'); try {
process.kill(proc.pid, 'SIGKILL');
}
catch (e) {
// Could already be dead and just needs to be waited on
this.logger.debug(
`Got error while SIGKILLing process ${proc}:`,
e
);
}
} else { } else {
stdout += data; stdout += data;
output += data; output += data;
@ -254,7 +281,7 @@ class Job {
if (this.state !== job_states.PRIMED) { if (this.state !== job_states.PRIMED) {
throw new Error( throw new Error(
'Job must be in primed state, current state: ' + 'Job must be in primed state, current state: ' +
this.state.toString() this.state.toString()
); );
} }
@ -271,22 +298,22 @@ class Job {
const { emit_event_bus_result, emit_event_bus_stage } = const { emit_event_bus_result, emit_event_bus_stage } =
event_bus === null event_bus === null
? { ? {
emit_event_bus_result: () => {}, emit_event_bus_result: () => { },
emit_event_bus_stage: () => {}, emit_event_bus_stage: () => { },
} }
: { : {
emit_event_bus_result: (stage, result, event_bus) => { emit_event_bus_result: (stage, result, event_bus) => {
const { error, code, signal } = result; const { error, code, signal } = result;
event_bus.emit('exit', stage, { event_bus.emit('exit', stage, {
error, error,
code, code,
signal, signal,
}); });
}, },
emit_event_bus_stage: (stage, event_bus) => { emit_event_bus_stage: (stage, event_bus) => {
event_bus.emit('stage', stage); event_bus.emit('stage', stage);
}, },
}; };
if (this.runtime.compiled) { if (this.runtime.compiled) {
this.logger.debug('Compiling'); this.logger.debug('Compiling');
@ -352,9 +379,9 @@ class Job {
const [_, ruid, euid, suid, fuid] = uid_line.split(/\s+/); const [_, ruid, euid, suid, fuid] = uid_line.split(/\s+/);
const [_1, state, user_friendly] = state_line.split(/\s+/); const [_1, state, user_friendly] = state_line.split(/\s+/);
const proc_id_int = parse_int(proc_id); const proc_id_int = parse_int(proc_id);
// Skip over any processes that aren't ours. // Skip over any processes that aren't ours.
if (ruid != this.uid && euid != this.uid) return -1; if (ruid != this.uid && euid != this.uid) return -1;
@ -362,7 +389,7 @@ class Job {
// Zombie process, just needs to be waited, regardless of the user id // Zombie process, just needs to be waited, regardless of the user id
if (!to_wait.includes(proc_id_int)) if (!to_wait.includes(proc_id_int))
to_wait.push(proc_id_int); to_wait.push(proc_id_int);
return -1; return -1;
} }
// We should kill in all other state (Sleep, Stopped & Running) // We should kill in all other state (Sleep, Stopped & Running)
@ -397,7 +424,7 @@ class Job {
// Then clear them out of the process tree // Then clear them out of the process tree
try { try {
process.kill(proc, 'SIGKILL'); process.kill(proc, 'SIGKILL');
} catch { } catch (e) {
// Could already be dead and just needs to be waited on // Could already be dead and just needs to be waited on
this.logger.debug( this.logger.debug(
`Got error while SIGKILLing process ${proc}:`, `Got error while SIGKILLing process ${proc}:`,