Skip to content

Commit 63e8e65

Browse files
committed
fix: allow detached respawn on Windows for /restart
restartGatewayProcessWithFreshPid() previously returned mode:disabled on Windows when no Scheduled Task markers were detected, causing /restart to fall back to in-process restart (HTTP server close+reopen) without actually restarting the Node.js process. The PID and uptime remained unchanged. The update restart path (respawnGatewayProcessForUpdate()) already attempts detached spawn on Windows. Apply the same behavior to the normal restart path so /restart works on unmanaged Windows installs.
1 parent 583829a commit 63e8e65

1 file changed

Lines changed: 14 additions & 6 deletions

File tree

src/infra/process-respawn.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ function spawnDetachedGatewayProcess(opts: GatewayRespawnOptions = {}): {
6161
* Attempt to restart this process with a fresh PID.
6262
* - supervised environments (launchd/systemd/schtasks): caller should exit and let supervisor restart
6363
* - OPENCLAW_NO_RESPAWN=1: caller should keep in-process restart behavior (tests/dev)
64+
* - Windows (no supervisor): attempts detached respawn so /restart actually restarts
6465
* - unmanaged environments: caller should keep in-process restart behavior so
6566
* custom supervisors keep tracking the same gateway PID
6667
*/
@@ -87,12 +88,19 @@ export function restartGatewayProcessWithFreshPid(
8788
return { mode: "supervised" };
8889
}
8990
if (process.platform === "win32") {
90-
// Detached respawn is unsafe on Windows without an identified Scheduled Task:
91-
// the child becomes orphaned if the original process exits.
92-
return {
93-
mode: "disabled",
94-
detail: "win32: detached respawn unsupported without Scheduled Task markers",
95-
};
91+
// Try detached respawn on Windows. Without a Scheduled Task supervisor the
92+
// child is technically orphaned, but a clean exit followed by spawn is the
93+
// only way to actually restart the process. The update path already allows
94+
// this — apply the same behaviour to normal restarts so /restart works.
95+
try {
96+
const { child, pid } = spawnDetachedGatewayProcess(_opts);
97+
return { mode: "spawned", pid, detail: "win32: detached respawn" };
98+
} catch (err) {
99+
return {
100+
mode: "failed",
101+
detail: `win32: detached respawn failed: ${formatErrorMessage(err)}`,
102+
};
103+
}
96104
}
97105
if (isContainerEnvironment()) {
98106
return {

0 commit comments

Comments
 (0)