// Allow extra time for draining active turns on restart. const forceExitMs = isRestart
? restartDrainTimeoutMs + SHUTDOWN_TIMEOUT_MS
: SHUTDOWN_TIMEOUT_MS; const forceExitTimer = setTimeout(() => {
gatewayLog.error("shutdown timed out; exiting without full cleanup");
writeStabilityBundle(
isRestart ? "gateway.restart_shutdown_timeout" : "gateway.stop_shutdown_timeout",
); // Keep the in-process watchdog below the supervisor stop budget so this // path wins before launchd/systemd escalates to a hard kill. Exit // non-zero on any timeout so supervised installs restart cleanly.
exitProcess(1);
}, forceExitMs);
void (async () => { try { // On restart, wait for in-flight agent turns to finish before // tearing down the server so buffered messages are delivered. if (isRestart) { // Reject new enqueues immediately during the drain window so // sessions get an explicit restart error instead of silent task loss.
markGatewayDraining(); const activeTasks = getActiveTaskCount(); const activeRuns = getActiveEmbeddedRunCount();
// Best-effort abort for compacting runs so long compaction operations // don't hold session write locks across restart boundaries. if (activeRuns > 0) {
abortEmbeddedPiRun(undefined, { mode: "compacting" });
}
if (activeTasks > 0 || activeRuns > 0) {
gatewayLog.info(
`draining ${activeTasks} active task(s) and ${activeRuns} active embedded run(s) before restart (timeout ${restartDrainTimeoutMs}ms)`,
); const [tasksDrain, runsDrain] = await Promise.all([
activeTasks > 0
? waitForActiveTasks(restartDrainTimeoutMs)
: Promise.resolve({ drained: true }),
activeRuns > 0
? waitForActiveEmbeddedRuns(restartDrainTimeoutMs)
: Promise.resolve({ drained: true }),
]); if (tasksDrain.drained && runsDrain.drained) {
gatewayLog.info("all active work drained");
} else {
gatewayLog.warn("drain timeout reached; proceeding with restart"); // Final best-effort abort to avoid carrying active runs into the // next lifecycle when drain time budget is exhausted.
abortEmbeddedPiRun(undefined, { mode: "all" });
}
}
}
try { const onIteration = createRestartIterationHook(() => { // After an in-process restart (SIGUSR1), reset command-queue lane state. // Interrupted tasks from the previous lifecycle may have left `active` // counts elevated (their finally blocks never ran), permanently blocking // new work from draining. This must happen here — at the restart // coordinator level — rather than inside individual subsystem init // functions, to avoid surprising cross-cutting side effects.
resetAllLanes();
});
// Keep process alive; SIGUSR1 triggers an in-process restart (no supervisor required). // SIGTERM/SIGINT still exit after a graceful shutdown.
let isFirstStart = true; for (;;) {
onIteration(); try {
server = await params.start({ startupStartedAt });
isFirstStart = false;
} catch (err) { // On initial startup, let the error propagate so the outer handler // can report "Gateway failed to start" and exit non-zero. Only // swallow errors on subsequent in-process restarts to keep the // process alive (a crash would lose macOS TCC permissions). (#35862) if (isFirstStart) { throw err;
}
server = null; // Release the gateway lock so that `daemon restart/stop` (which // discovers PIDs via the gateway port) can still manage the process. // Without this, the process holds the lock but is not listening, // forcing manual cleanup. (#35862)
await releaseLockIfHeld(); const errMsg = formatErrorMessage(err); const errStack = err instanceof Error && err.stack ? `\n${err.stack}` : "";
writeStabilityBundle("gateway.restart_startup_failed", err);
gatewayLog.error(
`gateway startup failed: ${errMsg}. ` +
`Process will stay alive; fix the issue and restart.${errStack}`,
);
}
await new Promise<void>((resolve) => {
restartResolver = resolve;
});
}
} finally {
await releaseLockIfHeld();
cleanupSignals();
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.