fix: recover matching durable image video submission receipts
This commit is contained in:
@@ -95,4 +95,46 @@ describe("durable image video tasks", () => {
|
||||
const receipt = JSON.parse(await readFile(join(f.options.root, task.id, "submission-receipt.json"), "utf8")) as { jobId: string };
|
||||
expect(receipt.jobId).toBe("late_job");
|
||||
});
|
||||
it("recovers a matching persisted submit receipt after restart and polls that job without resubmitting", async () => {
|
||||
const f = await fixture(); const task = await f.service.create("ses_owner", f.draft);
|
||||
await f.service.upload("ses_owner", task.id); await f.service.refresh(task.id);
|
||||
const file = join(f.options.root, task.id, "record.json"); const record = JSON.parse(await readFile(file, "utf8")) as ImageVideoRecord;
|
||||
record.state = "submitting"; record.revision++;
|
||||
await writeFile(file, JSON.stringify(record));
|
||||
await writeFile(join(f.options.root, task.id, "submission-receipt.json"), JSON.stringify({ version: 1, id: task.id, requestHash: record.requestHash, revision: record.revision, jobId: "accepted_before_crash" }));
|
||||
f.calls.length = 0;
|
||||
f.remote.status = (r) => { f.calls.push(`status:${r.jobId ?? "missing"}`); return Promise.resolve({ state: "running" }); };
|
||||
const restored = new harness.ImageVideoService(f.options);
|
||||
expect(await restored.view(task.id)).toMatchObject({ state: "queued", jobId: "accepted_before_crash" });
|
||||
expect(JSON.parse(await readFile(file, "utf8")) as ImageVideoRecord).toMatchObject({ state: "queued", jobId: "accepted_before_crash", revision: record.revision + 1 });
|
||||
expect(await restored.refresh(task.id)).toMatchObject({ state: "running", jobId: "accepted_before_crash" });
|
||||
await new harness.ImageVideoService(f.options).submit("ses_owner", task.id);
|
||||
expect(f.calls).toEqual(["status:accepted_before_crash"]);
|
||||
});
|
||||
it.each(["task", "hash", "stale", "future", "malformed", "empty_job", "version", "extra_field", "conflicting_job"] as const)("quarantines a %s receipt without polling it or submitting again", async (kind) => {
|
||||
const f = await fixture(); const task = await f.service.create("ses_owner", f.draft);
|
||||
await f.service.upload("ses_owner", task.id); await f.service.refresh(task.id);
|
||||
const file = join(f.options.root, task.id, "record.json"); const record = JSON.parse(await readFile(file, "utf8")) as ImageVideoRecord;
|
||||
record.state = "submitting"; record.revision++;
|
||||
delete record.lastPollAt;
|
||||
if (kind === "conflicting_job") record.jobId = "different_record_job";
|
||||
const receipt: Record<string, unknown> = { version: 1, id: task.id, requestHash: record.requestHash, revision: record.revision, jobId: "untrusted_receipt_job" };
|
||||
if (kind === "task") receipt.id = "i2v_11111111-1111-1111-1111-111111111111";
|
||||
if (kind === "hash") receipt.requestHash = "a".repeat(64);
|
||||
if (kind === "stale") receipt.revision = record.revision - 1;
|
||||
if (kind === "future") receipt.revision = record.revision + 1;
|
||||
if (kind === "empty_job") receipt.jobId = "";
|
||||
if (kind === "version") receipt.version = 2;
|
||||
if (kind === "extra_field") receipt.unexpected = "conflicting format";
|
||||
const serialized = kind === "malformed" ? "{broken-json" : JSON.stringify(receipt);
|
||||
await writeFile(file, JSON.stringify(record));
|
||||
const receiptPath = join(f.options.root, task.id, "submission-receipt.json"); await writeFile(receiptPath, serialized);
|
||||
f.calls.length = 0;
|
||||
const restored = new harness.ImageVideoService(f.options);
|
||||
expect((await restored.view(task.id)).state).toBe("unknown_submission");
|
||||
expect((await restored.refresh(task.id)).state).toBe("unknown_submission");
|
||||
await expect(restored.submit("ses_owner", task.id)).rejects.toMatchObject({ code: "I2V_UNKNOWN_SUBMISSION" });
|
||||
expect(f.calls).toEqual([]);
|
||||
expect(await readFile(receiptPath, "utf8")).toBe(serialized);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user