| @@ -21,14 +21,61 @@ export function startProcess(command, args, options = {}) { | |||||
| return { child, output }; | 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); | |||||
| } | |||||