




















@@ -136,6 +136,30 @@ describe("cron store", () => {
136136expect(loaded.jobs[0]?.enabled).toBe(true);
137137});
138138139+it("skips non-object persisted jobs instead of hydrating scalar rows", async () => {
140+const store = await makeStorePath();
141+const valid = makeStore("job-valid", true).jobs[0];
142+await fs.mkdir(path.dirname(store.storePath), { recursive: true });
143+await fs.writeFile(
144+store.storePath,
145+JSON.stringify(
146+{
147+version: 1,
148+jobs: ["bad-row", 7, null, false, valid],
149+},
150+null,
151+2,
152+),
153+"utf-8",
154+);
155+156+const loaded = await loadCronStore(store.storePath);
157+158+expect(loaded.jobs).toHaveLength(1);
159+expect(loaded.jobs[0]?.id).toBe("job-valid");
160+expect(loaded.jobs[0]?.state).toStrictEqual({});
161+});
162+139163it("loads split cron state synchronously for task reconciliation", async () => {
140164const { storePath } = await makeStorePath();
141165await saveCronStore(storePath, makeStore("job-sync", true));
@@ -526,6 +550,48 @@ describe("cron store", () => {
526550expect(loaded.jobs[0]?.state.nextRunAtMs).toBe(job.createdAtMs + 60_000);
527551});
528552553+it("drops non-object runtime state from split cron sidecars", async () => {
554+const store = await makeStorePath();
555+const first = makeStore("job-array-state", true).jobs[0];
556+const second = makeStore("job-scalar-entry", true).jobs[0];
557+const config = {
558+version: 1,
559+jobs: [
560+{ ...first, state: {}, updatedAtMs: undefined },
561+{ ...second, state: {}, updatedAtMs: undefined },
562+],
563+};
564+const statePath = store.storePath.replace(/\.json$/, "-state.json");
565+566+await fs.mkdir(path.dirname(store.storePath), { recursive: true });
567+await fs.writeFile(store.storePath, JSON.stringify(config, null, 2), "utf-8");
568+await fs.writeFile(
569+statePath,
570+JSON.stringify(
571+{
572+version: 1,
573+jobs: {
574+[first.id]: {
575+updatedAtMs: first.createdAtMs + 60_000,
576+state: ["not", "state"],
577+},
578+[second.id]: "not-an-entry",
579+},
580+},
581+null,
582+2,
583+),
584+"utf-8",
585+);
586+587+const loaded = await loadCronStore(store.storePath);
588+589+expect(loaded.jobs[0]?.updatedAtMs).toBe(first.createdAtMs + 60_000);
590+expect(loaded.jobs[0]?.state).toStrictEqual({});
591+expect(loaded.jobs[1]?.updatedAtMs).toBe(second.createdAtMs);
592+expect(loaded.jobs[1]?.state).toStrictEqual({});
593+});
594+529595it.skipIf(process.platform === "win32")(
530596"writes store and backup files with secure permissions",
531597async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。