mirror of
https://github.com/EveryInc/compound-engineering-plugin.git
synced 2026-10-30 20:15:09 +01:00
33 lines
1.1 KiB
TypeScript
33 lines
1.1 KiB
TypeScript
import { spawnSync } from "node:child_process"
|
|
|
|
/**
|
|
* True while a process with this pid is running. A zombie counts as gone:
|
|
* kill(pid, 0) still succeeds for one, and a container whose PID 1 does not
|
|
* reap adopted orphans can leave a killed process as a zombie indefinitely.
|
|
*/
|
|
export function alive(pid: number): boolean {
|
|
try {
|
|
process.kill(pid, 0)
|
|
} catch {
|
|
return false
|
|
}
|
|
const state = spawnSync("ps", ["-o", "stat=", "-p", String(pid)], { encoding: "utf8" })
|
|
if (state.status !== 0 && !state.stdout?.trim()) return false
|
|
return !state.stdout.trim().startsWith("Z")
|
|
}
|
|
|
|
/**
|
|
* Returns the pids still alive once all have exited or `timeoutMs` passes.
|
|
* A process SIGKILLed just before its killer exits can still be running for a
|
|
* moment on a loaded runner; checking at one instant flakes, so poll instead.
|
|
*/
|
|
export async function survivors(pids: number[], timeoutMs = 5_000): Promise<number[]> {
|
|
const deadline = Date.now() + timeoutMs
|
|
let left = pids.filter(alive)
|
|
while (left.length > 0 && Date.now() < deadline) {
|
|
await Bun.sleep(50)
|
|
left = left.filter(alive)
|
|
}
|
|
return left
|
|
}
|