47 lines
1.5 KiB
JavaScript
47 lines
1.5 KiB
JavaScript
import { spawn } from "bun";
|
|
// Only the "supervisor" respawns. The child sets this env var so it won't respawn itself.
|
|
const IS_CHILD = process.env.__RESPAWN_CHILD === "1";
|
|
let shuttingDown = false;
|
|
async function cleanup() {
|
|
// Put real cleanup here: close DB handles, servers, file descriptors, timers, etc.
|
|
// Must be awaitable — do NOT rely on process.on("exit") for this.
|
|
}
|
|
function respawn(code) {
|
|
const child = spawn({
|
|
cmd: [process.execPath, ...process.argv.slice(1)],
|
|
stdio: ["inherit", "inherit", "inherit"],
|
|
env: { ...process.env, __RESPAWN_CHILD: "1" },
|
|
// Detach so the child survives independently and gets its own process group.
|
|
// Without this, killing the parent's group can take the child with it.
|
|
});
|
|
// Let the child live on its own.
|
|
child.unref?.();
|
|
}
|
|
async function shutdown(code) {
|
|
if (shuttingDown)
|
|
return;
|
|
shuttingDown = true;
|
|
try {
|
|
await cleanup();
|
|
}
|
|
catch (e) {
|
|
console.error("cleanup failed:", e);
|
|
}
|
|
// Only the supervisor respawns, and only on abnormal exit.
|
|
if (!IS_CHILD && code !== 0) {
|
|
respawn(code);
|
|
}
|
|
process.exit(code);
|
|
}
|
|
// Catch the things that actually fire *before* exit, where async works.
|
|
process.on("SIGINT", () => shutdown(130));
|
|
process.on("SIGTERM", () => shutdown(143));
|
|
process.on("uncaughtException", (err) => {
|
|
console.error(err);
|
|
shutdown(1);
|
|
});
|
|
process.on("unhandledRejection", (err) => {
|
|
console.error(err);
|
|
shutdown(1);
|
|
});
|