mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 22:14:34 +00:00
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 os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { describe, expect, it } from "vitest";
|
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", () => {
|
describe("schtasks runtime parsing", () => {
|
||||||
it.each(["Ready", "Running"])("parses %s status", (status) => {
|
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", () => {
|
describe("resolveTaskScriptPath", () => {
|
||||||
it.each([
|
it.each([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -132,6 +132,53 @@ export function parseSchtasksQuery(output: string): ScheduledTaskInfo {
|
|||||||
return info;
|
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({
|
function buildTaskScript({
|
||||||
description,
|
description,
|
||||||
programArguments,
|
programArguments,
|
||||||
@@ -307,12 +354,12 @@ export async function readScheduledTaskRuntime(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const parsed = parseSchtasksQuery(res.stdout || "");
|
const parsed = parseSchtasksQuery(res.stdout || "");
|
||||||
const statusRaw = parsed.status?.toLowerCase();
|
const derived = deriveScheduledTaskRuntimeStatus(parsed);
|
||||||
const status = statusRaw === "running" ? "running" : statusRaw ? "stopped" : "unknown";
|
|
||||||
return {
|
return {
|
||||||
status,
|
status: derived.status,
|
||||||
state: parsed.status,
|
state: parsed.status,
|
||||||
lastRunTime: parsed.lastRunTime,
|
lastRunTime: parsed.lastRunTime,
|
||||||
lastRunResult: parsed.lastRunResult,
|
lastRunResult: parsed.lastRunResult,
|
||||||
|
...(derived.detail ? { detail: derived.detail } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user