feat(cms): add recovery history and operational reliability tools
CI / check (push) Failing after 22s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

This commit is contained in:
Simo committed 2026-09-09 21:57:56 +02:00
1 parent 89526af344
commit 1ef405be0a
92 files changed
+6384 -267

No files matched your search

+101
View File
@@ -100,3 +100,104 @@ it("loads bounded history for the requesting owner", async () => {
expect(result).toHaveLength(2);
expect(result.every((job) => job.userId === 4)).toBe(true);
});
it("keeps history pages stable while an older job changes", async () => {
const s = await store();
const older = { ...job(), createdAt: "2026-01-01T00:00:00.000Z" };
const newer = { ...job(), createdAt: "2026-01-02T00:00:00.000Z" };
await s.create(older);
await s.create(newer);
const first = await s.page({ userId: 4, limit: 1 });
expect(first.jobs.map((j) => j.id)).toEqual([newer.id]);
await s.save({ ...older, state: "completed" });
const second = await s.page({
userId: 4,
limit: 1,
before: first.nextCursor ?? undefined,
});
expect(second.jobs.map((j) => j.id)).toEqual([older.id]);
expect(second.nextCursor).toBeNull();
});
it("creates a single retry across concurrent requests and excludes successful items", async () => {
const s = await store();
const original = {
...job(),
state: "completed" as const,
items: [
{
id: 1,
classname: "chair",
name: "Chair",
description: "",
type: "flooritem",
revision: 1,
category: "",
state: "failed" as const,
},
{
id: 2,
classname: "lamp",
name: "Lamp",
description: "",
type: "flooritem",
revision: 1,
category: "",
state: "done" as const,
},
],
};
await s.create(original);
const [a, b] = await Promise.all([
s.retry(original.id, 4),
s.retry(original.id, 4),
]);
expect(a?.id).toBe(b?.id);
expect(a?.items.map((i) => i.classname)).toEqual(["chair"]);
expect(await s.list()).toHaveLength(2);
expect(await s.retry(original.id, 99)).toBeNull();
});
it("does not retry active jobs or uncertain outcomes", async () => {
const s = await store();
const original = {
...job(),
items: [
{
id: 1,
classname: "chair",
name: "Chair",
description: "",
type: "flooritem",
revision: 1,
category: "",
state: "interrupted" as const,
},
],
};
await s.create(original);
expect(await s.retry(original.id, 4)).toBeNull();
await s.save({ ...original, state: "interrupted" });
expect(await s.retry(original.id, 4)).toBeNull();
expect(await s.list()).toHaveLength(1);
});
it("paginates timestamp ties without duplicates and excludes other owners", async () => {
const s = await store();
const createdAt = "2026-01-01T00:00:00.000Z";
const own = [
{ ...job(), createdAt },
{ ...job(), createdAt },
{ ...job(), createdAt },
];
for (const entry of [...own, { ...job(), createdAt, userId: 99 }])
await s.create(entry);
const first = await s.page({ userId: 4, limit: 2 });
const second = await s.page({
userId: 4,
limit: 2,
before: first.nextCursor ?? undefined,
});
expect(new Set([...first.jobs, ...second.jobs].map((j) => j.id))).toEqual(
new Set(own.map((j) => j.id)),
);
expect(first.jobs.length + second.jobs.length).toBe(3);
});