|
|
|
@@ -21,14 +21,61 @@ export function startProcess(command, args, options = {}) { |
|
|
|
return { child, output }; |
|
|
|
} |
|
|
|
|
|
|
|
export async function stopProcess(child) { |
|
|
|
if (!child || child.killed) return; |
|
|
|
await new Promise((resolve) => { |
|
|
|
child.once('exit', resolve); |
|
|
|
child.kill(process.platform === 'win32' ? undefined : 'SIGTERM'); |
|
|
|
setTimeout(() => { |
|
|
|
if (!child.killed) child.kill('SIGKILL'); |
|
|
|
resolve(); |
|
|
|
}, 5000).unref(); |
|
|
|
function hasExited(child) { |
|
|
|
return child.exitCode !== null || child.signalCode !== null; |
|
|
|
} |
|
|
|
|
|
|
|
function waitForExit(child, timeoutMs) { |
|
|
|
if (!child || hasExited(child)) return Promise.resolve(true); |
|
|
|
|
|
|
|
return new Promise((resolve) => { |
|
|
|
let settled = false; |
|
|
|
let timer; |
|
|
|
|
|
|
|
const finish = (exited) => { |
|
|
|
if (settled) return; |
|
|
|
settled = true; |
|
|
|
clearTimeout(timer); |
|
|
|
child.off('exit', onExit); |
|
|
|
child.off('close', onExit); |
|
|
|
resolve(exited); |
|
|
|
}; |
|
|
|
|
|
|
|
const onExit = () => finish(true); |
|
|
|
|
|
|
|
child.once('exit', onExit); |
|
|
|
child.once('close', onExit); |
|
|
|
timer = setTimeout(() => finish(false), timeoutMs); |
|
|
|
timer.unref(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function killWindowsProcessTree(pid) { |
|
|
|
if (!pid) return Promise.resolve(); |
|
|
|
|
|
|
|
return new Promise((resolve) => { |
|
|
|
const killer = spawn('taskkill', ['/PID', String(pid), '/T', '/F'], { |
|
|
|
stdio: 'ignore', |
|
|
|
}); |
|
|
|
|
|
|
|
killer.once('error', resolve); |
|
|
|
killer.once('exit', resolve); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
export async function stopProcess(child) { |
|
|
|
if (!child || hasExited(child)) return; |
|
|
|
|
|
|
|
if (process.platform === 'win32') { |
|
|
|
await killWindowsProcessTree(child.pid); |
|
|
|
await waitForExit(child, 5000); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
child.kill('SIGTERM'); |
|
|
|
const exited = await waitForExit(child, 5000); |
|
|
|
if (exited) return; |
|
|
|
|
|
|
|
child.kill('SIGKILL'); |
|
|
|
await waitForExit(child, 5000); |
|
|
|
} |