|
|
|
@@ -12,6 +12,10 @@ export function startProcess(command, args, options = {}) { |
|
|
|
child.stdout.on('data', (chunk) => output.push(chunk.toString())); |
|
|
|
child.stderr.on('data', (chunk) => output.push(chunk.toString())); |
|
|
|
|
|
|
|
child.once('error', (error) => { |
|
|
|
output.push(`\nprocess failed to start: ${error.message}\n`); |
|
|
|
}); |
|
|
|
|
|
|
|
child.once('exit', (code) => { |
|
|
|
if (code !== null && code !== 0) { |
|
|
|
output.push(`\nprocess exited with code ${code}\n`); |
|
|
|
@@ -25,6 +29,17 @@ function hasExited(child) { |
|
|
|
return child.exitCode !== null || child.signalCode !== null; |
|
|
|
} |
|
|
|
|
|
|
|
function sendSignal(child, signal) { |
|
|
|
if (!child || hasExited(child)) return false; |
|
|
|
|
|
|
|
try { |
|
|
|
return child.kill(signal); |
|
|
|
} catch (error) { |
|
|
|
if (error?.code === 'ESRCH' || hasExited(child)) return false; |
|
|
|
throw error; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function waitForExit(child, timeoutMs) { |
|
|
|
if (!child || hasExited(child)) return Promise.resolve(true); |
|
|
|
|
|
|
|
@@ -72,10 +87,10 @@ export async function stopProcess(child) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
child.kill('SIGTERM'); |
|
|
|
sendSignal(child, 'SIGTERM'); |
|
|
|
const exited = await waitForExit(child, 5000); |
|
|
|
if (exited) return; |
|
|
|
|
|
|
|
child.kill('SIGKILL'); |
|
|
|
sendSignal(child, 'SIGKILL'); |
|
|
|
await waitForExit(child, 5000); |
|
|
|
} |