Files
openclaw/src/infra/windows-task-restart.ts

73 lines
2.3 KiB
TypeScript

import { spawn } from "node:child_process";
import { randomUUID } from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { quoteCmdScriptArg } from "../daemon/cmd-argv.js";
import { resolveGatewayWindowsTaskName } from "../daemon/constants.js";
import type { RestartAttempt } from "./restart.js";
import { resolvePreferredOpenClawTmpDir } from "./tmp-openclaw-dir.js";
const TASK_RESTART_RETRY_LIMIT = 12;
const TASK_RESTART_RETRY_DELAY_SEC = 1;
function resolveWindowsTaskName(env: NodeJS.ProcessEnv): string {
const override = env.OPENCLAW_WINDOWS_TASK_NAME?.trim();
if (override) {
return override;
}
return resolveGatewayWindowsTaskName(env.OPENCLAW_PROFILE);
}
function buildScheduledTaskRestartScript(taskName: string): string {
const quotedTaskName = quoteCmdScriptArg(taskName);
return [
"@echo off",
"setlocal",
"set /a attempts=0",
":retry",
`timeout /t ${TASK_RESTART_RETRY_DELAY_SEC} /nobreak >nul`,
"set /a attempts+=1",
`schtasks /Run /TN ${quotedTaskName} >nul 2>&1`,
"if not errorlevel 1 goto cleanup",
`if %attempts% GEQ ${TASK_RESTART_RETRY_LIMIT} goto cleanup`,
"goto retry",
":cleanup",
'del "%~f0" >nul 2>&1',
].join("\r\n");
}
export function relaunchGatewayScheduledTask(env: NodeJS.ProcessEnv = process.env): RestartAttempt {
const taskName = resolveWindowsTaskName(env);
const scriptPath = path.join(
resolvePreferredOpenClawTmpDir(),
`openclaw-schtasks-restart-${randomUUID()}.cmd`,
);
const quotedScriptPath = quoteCmdScriptArg(scriptPath);
try {
fs.writeFileSync(scriptPath, `${buildScheduledTaskRestartScript(taskName)}\r\n`, "utf8");
const child = spawn("cmd.exe", ["/d", "/s", "/c", quotedScriptPath], {
detached: true,
stdio: "ignore",
windowsHide: true,
});
child.unref();
return {
ok: true,
method: "schtasks",
tried: [`schtasks /Run /TN "${taskName}"`, `cmd.exe /d /s /c ${quotedScriptPath}`],
};
} catch (err) {
try {
fs.unlinkSync(scriptPath);
} catch {
// Best-effort cleanup; keep the original restart failure.
}
return {
ok: false,
method: "schtasks",
detail: err instanceof Error ? err.message : String(err),
tried: [`schtasks /Run /TN "${taskName}"`],
};
}
}