fix(gateway): handle Windows OpenClaw process exit error during in-process restarts (#794)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Haze <hazeone@users.noreply.github.com>
This commit is contained in:
Haze
2026-04-08 12:06:12 +08:00
committed by GitHub
Unverified
parent 3021ad5089
commit 32d14b8cf9
8 changed files with 687 additions and 24 deletions

View File

@@ -12,6 +12,8 @@ type StartupHooks = {
ownedPid?: never; // Removed: pid is now read dynamically in findExistingGateway to avoid stale-snapshot bug
shouldWaitForPortFree: boolean;
maxStartAttempts?: number;
/** Returns true when the manager still owns a living Gateway process (e.g. after a code-1012 in-process restart). */
hasOwnedProcess: () => boolean;
resetStartupStderrLines: () => void;
getStartupStderrLines: () => string[];
assertLifecycle: (phase: string) => void;
@@ -49,6 +51,22 @@ export async function runGatewayStartupSequence(hooks: StartupHooks): Promise<vo
return;
}
// When the Gateway did an in-process restart (WS close 1012), the
// UtilityProcess is still alive but its WS server may be mid-rebuild,
// so findExistingGateway's quick probe returns null. Rather than
// waiting for the port to free (it never will — the process holds it)
// and then spawning a duplicate, wait for the existing process to
// become ready and reconnect to it.
if (hooks.hasOwnedProcess()) {
logger.info('Owned Gateway process still alive (likely in-process restart); waiting for it to become ready');
await hooks.waitForReady(hooks.port);
hooks.assertLifecycle('start/wait-ready-owned');
await hooks.connect(hooks.port);
hooks.assertLifecycle('start/connect-owned');
hooks.onConnectedToExistingGateway();
return;
}
logger.debug('No existing Gateway found, starting new process...');
if (hooks.shouldWaitForPortFree) {