mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-30 12:51:03 +00:00
fix(cron): canonicalize preserved row ids
This commit is contained in:
committed by
Peter Steinberger
parent
c916906584
commit
985bc934a1
@@ -223,6 +223,82 @@ describe("cron service store seam coverage", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("skips preserved unsupported rows that collide with supported jobs by canonical id", async () => {
|
||||
const { storePath } = await makeStorePath();
|
||||
|
||||
await writeJobStore(storePath, [
|
||||
{
|
||||
id: "trimmed-collision",
|
||||
name: "supported trimmed collision",
|
||||
enabled: true,
|
||||
createdAtMs: STORE_TEST_NOW - 60_000,
|
||||
updatedAtMs: STORE_TEST_NOW - 60_000,
|
||||
schedule: { kind: "every", everyMs: 60_000 },
|
||||
sessionTarget: "main",
|
||||
wakeMode: "now",
|
||||
payload: { kind: "systemEvent", text: "tick" },
|
||||
state: {},
|
||||
},
|
||||
{
|
||||
id: " trimmed-collision ",
|
||||
name: "stale unsupported padded id",
|
||||
enabled: true,
|
||||
createdAtMs: STORE_TEST_NOW - 60_000,
|
||||
schedule: { kind: "cron", expr: "0 8 * * *", tz: "UTC" },
|
||||
sessionTarget: "main",
|
||||
wakeMode: "now",
|
||||
payload: { kind: "command", command: "echo stale" },
|
||||
},
|
||||
{
|
||||
id: "legacy-jobid-collision",
|
||||
name: "supported legacy jobId collision",
|
||||
enabled: true,
|
||||
createdAtMs: STORE_TEST_NOW - 60_000,
|
||||
updatedAtMs: STORE_TEST_NOW - 60_000,
|
||||
schedule: { kind: "every", everyMs: 120_000 },
|
||||
sessionTarget: "main",
|
||||
wakeMode: "now",
|
||||
payload: { kind: "systemEvent", text: "tick legacy" },
|
||||
state: {},
|
||||
},
|
||||
{
|
||||
jobId: " legacy-jobid-collision ",
|
||||
name: "stale unsupported legacy jobId",
|
||||
enabled: true,
|
||||
createdAtMs: STORE_TEST_NOW - 60_000,
|
||||
schedule: { kind: "cron", expr: "0 9 * * *", tz: "UTC" },
|
||||
sessionTarget: "main",
|
||||
wakeMode: "now",
|
||||
payload: { kind: "agentmessage", message: "summarize stale" },
|
||||
},
|
||||
]);
|
||||
|
||||
const state = createStoreTestState(storePath);
|
||||
await ensureLoaded(state, { skipRecompute: true });
|
||||
|
||||
expect(state.store?.jobs.map((job) => job.id)).toEqual([
|
||||
"trimmed-collision",
|
||||
"legacy-jobid-collision",
|
||||
]);
|
||||
|
||||
await persist(state);
|
||||
|
||||
const config = JSON.parse(await fs.readFile(storePath, "utf8")) as {
|
||||
jobs: Array<Record<string, unknown>>;
|
||||
};
|
||||
expect(config.jobs.map((job) => job.id)).toEqual([
|
||||
"trimmed-collision",
|
||||
"legacy-jobid-collision",
|
||||
]);
|
||||
expect(config.jobs.map((job) => job.name)).toEqual([
|
||||
"supported trimmed collision",
|
||||
"supported legacy jobId collision",
|
||||
]);
|
||||
expect(config.jobs.some((job) => job.jobId === " legacy-jobid-collision ")).toBe(false);
|
||||
expect(config.jobs.some((job) => job.name === "stale unsupported padded id")).toBe(false);
|
||||
expect(config.jobs.some((job) => job.name === "stale unsupported legacy jobId")).toBe(false);
|
||||
});
|
||||
|
||||
it("normalizes jobId-only jobs in memory so scheduler lookups resolve by stable id", async () => {
|
||||
const { storePath } = await makeStorePath();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { expandHomePrefix } from "../infra/home-dir.js";
|
||||
import { replaceFileAtomic } from "../infra/replace-file.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { resolveConfigDir } from "../utils.js";
|
||||
import { parseJsonWithJson5Fallback } from "../utils/parse-json-compat.js";
|
||||
import { tryCronScheduleIdentity } from "./schedule-identity.js";
|
||||
@@ -86,8 +87,7 @@ function stripJobRuntimeFields(job: CronStoreFile["jobs"][number]): Record<strin
|
||||
}
|
||||
|
||||
function persistedJobId(job: Record<string, unknown>): string | null {
|
||||
const id = job.id;
|
||||
return typeof id === "string" && id.trim() ? id : null;
|
||||
return normalizeOptionalString(job.id) ?? normalizeOptionalString(job.jobId) ?? null;
|
||||
}
|
||||
|
||||
function mergePreservedConfigJobs(
|
||||
|
||||
Reference in New Issue
Block a user