mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-17 12:11:20 +00:00
fix: preserve Windows scheduled task restart/install behavior (#59335) (thanks @tmimmanuel)
* fix(daemon): preserve Windows Task Scheduler settings on reinstall and exit early on failed restart * fix(daemon): add test coverage for Create/Change paths, fix early exit grace period * fix(daemon): fix startup-fallback tests for new isRegisteredScheduledTask call * fix(daemon): report early restart failure accurately * fix: preserve Windows scheduled task restart/install behavior (#59335) (thanks @tmimmanuel) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
import {
|
||||
DEFAULT_RESTART_HEALTH_ATTEMPTS,
|
||||
DEFAULT_RESTART_HEALTH_DELAY_MS,
|
||||
type GatewayRestartSnapshot,
|
||||
renderGatewayPortHealthDiagnostics,
|
||||
renderRestartDiagnostics,
|
||||
terminateStaleGatewayPids,
|
||||
@@ -31,6 +32,25 @@ import type { DaemonLifecycleOptions } from "./types.js";
|
||||
const POST_RESTART_HEALTH_ATTEMPTS = DEFAULT_RESTART_HEALTH_ATTEMPTS;
|
||||
const POST_RESTART_HEALTH_DELAY_MS = DEFAULT_RESTART_HEALTH_DELAY_MS;
|
||||
|
||||
function formatRestartFailure(params: {
|
||||
health: GatewayRestartSnapshot;
|
||||
port: number;
|
||||
timeoutSeconds: number;
|
||||
}): { statusLine: string; failMessage: string } {
|
||||
if (params.health.waitOutcome === "stopped-free") {
|
||||
const elapsedSeconds = Math.max(1, Math.round((params.health.elapsedMs ?? 0) / 1000));
|
||||
return {
|
||||
statusLine: `Gateway restart failed after ${elapsedSeconds}s: service stayed stopped and port ${params.port} stayed free.`,
|
||||
failMessage: `Gateway restart failed after ${elapsedSeconds}s: service stayed stopped and health checks never came up.`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
statusLine: `Timed out after ${params.timeoutSeconds}s waiting for gateway port ${params.port} to become healthy.`,
|
||||
failMessage: `Gateway restart timed out after ${params.timeoutSeconds}s waiting for health checks.`,
|
||||
};
|
||||
}
|
||||
|
||||
async function resolveGatewayLifecyclePort(service = resolveGatewayService()) {
|
||||
const command = await service.readCommand(process.env).catch(() => null);
|
||||
const serviceEnv = command?.environment ?? undefined;
|
||||
@@ -234,13 +254,17 @@ export async function runDaemonRestart(opts: DaemonLifecycleOptions = {}): Promi
|
||||
}
|
||||
|
||||
const diagnostics = renderRestartDiagnostics(health);
|
||||
const timeoutLine = `Timed out after ${restartWaitSeconds}s waiting for gateway port ${restartPort} to become healthy.`;
|
||||
const failure = formatRestartFailure({
|
||||
health,
|
||||
port: restartPort,
|
||||
timeoutSeconds: restartWaitSeconds,
|
||||
});
|
||||
const runningNoPortLine =
|
||||
health.runtime.status === "running" && health.portUsage.status === "free"
|
||||
? `Gateway process is running but port ${restartPort} is still free (startup hang/crash loop or very slow VM startup).`
|
||||
: null;
|
||||
if (!json) {
|
||||
defaultRuntime.log(theme.warn(timeoutLine));
|
||||
defaultRuntime.log(theme.warn(failure.statusLine));
|
||||
if (runningNoPortLine) {
|
||||
defaultRuntime.log(theme.warn(runningNoPortLine));
|
||||
}
|
||||
@@ -248,14 +272,14 @@ export async function runDaemonRestart(opts: DaemonLifecycleOptions = {}): Promi
|
||||
defaultRuntime.log(theme.muted(line));
|
||||
}
|
||||
} else {
|
||||
warnings.push(timeoutLine);
|
||||
warnings.push(failure.statusLine);
|
||||
if (runningNoPortLine) {
|
||||
warnings.push(runningNoPortLine);
|
||||
}
|
||||
warnings.push(...diagnostics);
|
||||
}
|
||||
|
||||
fail(`Gateway restart timed out after ${restartWaitSeconds}s waiting for health checks.`, [
|
||||
fail(failure.failMessage, [
|
||||
formatCliCommand("openclaw gateway status --deep"),
|
||||
formatCliCommand("openclaw doctor"),
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user