fix(gateway): avoid stale running status from Windows Scheduled Task (openclaw#19504) thanks @Fologan
Verified: - pnpm vitest src/daemon/schtasks.test.ts - pnpm check - pnpm build Co-authored-by: Fologan <164580328+Fologan@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,12 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parseSchtasksQuery, readScheduledTaskCommand, resolveTaskScriptPath } from "./schtasks.js";
|
||||
import {
|
||||
deriveScheduledTaskRuntimeStatus,
|
||||
parseSchtasksQuery,
|
||||
readScheduledTaskCommand,
|
||||
resolveTaskScriptPath,
|
||||
} from "./schtasks.js";
|
||||
|
||||
describe("schtasks runtime parsing", () => {
|
||||
it.each(["Ready", "Running"])("parses %s status", (status) => {
|
||||
@@ -20,6 +25,46 @@ describe("schtasks runtime parsing", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("scheduled task runtime derivation", () => {
|
||||
it("treats Running + 0x41301 as running", () => {
|
||||
expect(
|
||||
deriveScheduledTaskRuntimeStatus({
|
||||
status: "Running",
|
||||
lastRunResult: "0x41301",
|
||||
}),
|
||||
).toEqual({ status: "running" });
|
||||
});
|
||||
|
||||
it("treats Running + decimal 267009 as running", () => {
|
||||
expect(
|
||||
deriveScheduledTaskRuntimeStatus({
|
||||
status: "Running",
|
||||
lastRunResult: "267009",
|
||||
}),
|
||||
).toEqual({ status: "running" });
|
||||
});
|
||||
|
||||
it("treats Running without last result as running", () => {
|
||||
expect(
|
||||
deriveScheduledTaskRuntimeStatus({
|
||||
status: "Running",
|
||||
}),
|
||||
).toEqual({ status: "running" });
|
||||
});
|
||||
|
||||
it("downgrades stale Running status when last result is not a running code", () => {
|
||||
expect(
|
||||
deriveScheduledTaskRuntimeStatus({
|
||||
status: "Running",
|
||||
lastRunResult: "0x0",
|
||||
}),
|
||||
).toEqual({
|
||||
status: "stopped",
|
||||
detail: "Task reports Running but Last Run Result=0x0; treating as stale runtime state.",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveTaskScriptPath", () => {
|
||||
it.each([
|
||||
{
|
||||
|
||||
@@ -132,6 +132,53 @@ export function parseSchtasksQuery(output: string): ScheduledTaskInfo {
|
||||
return info;
|
||||
}
|
||||
|
||||
function normalizeTaskResultCode(value?: string): string | null {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const raw = value.trim().toLowerCase();
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (/^0x[0-9a-f]+$/.test(raw)) {
|
||||
return `0x${raw.slice(2).replace(/^0+/, "") || "0"}`;
|
||||
}
|
||||
|
||||
if (/^\d+$/.test(raw)) {
|
||||
const numeric = Number.parseInt(raw, 10);
|
||||
if (Number.isFinite(numeric)) {
|
||||
return `0x${numeric.toString(16)}`;
|
||||
}
|
||||
}
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
export function deriveScheduledTaskRuntimeStatus(parsed: ScheduledTaskInfo): {
|
||||
status: GatewayServiceRuntime["status"];
|
||||
detail?: string;
|
||||
} {
|
||||
const statusRaw = parsed.status?.trim().toLowerCase();
|
||||
if (!statusRaw) {
|
||||
return { status: "unknown" };
|
||||
}
|
||||
if (statusRaw !== "running") {
|
||||
return { status: "stopped" };
|
||||
}
|
||||
|
||||
const normalizedResult = normalizeTaskResultCode(parsed.lastRunResult);
|
||||
const runningCodes = new Set(["0x41301"]);
|
||||
if (normalizedResult && !runningCodes.has(normalizedResult)) {
|
||||
return {
|
||||
status: "stopped",
|
||||
detail: `Task reports Running but Last Run Result=${parsed.lastRunResult}; treating as stale runtime state.`,
|
||||
};
|
||||
}
|
||||
|
||||
return { status: "running" };
|
||||
}
|
||||
|
||||
function buildTaskScript({
|
||||
description,
|
||||
programArguments,
|
||||
@@ -307,12 +354,12 @@ export async function readScheduledTaskRuntime(
|
||||
};
|
||||
}
|
||||
const parsed = parseSchtasksQuery(res.stdout || "");
|
||||
const statusRaw = parsed.status?.toLowerCase();
|
||||
const status = statusRaw === "running" ? "running" : statusRaw ? "stopped" : "unknown";
|
||||
const derived = deriveScheduledTaskRuntimeStatus(parsed);
|
||||
return {
|
||||
status,
|
||||
status: derived.status,
|
||||
state: parsed.status,
|
||||
lastRunTime: parsed.lastRunTime,
|
||||
lastRunResult: parsed.lastRunResult,
|
||||
...(derived.detail ? { detail: derived.detail } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user