43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
// Resume only server-recorded enhancement jobs. A lost request without an upstream ID is never resubmitted.
|
|
export type RecoveryTask = {
|
|
status: string;
|
|
createdAt: string;
|
|
updatedAt?: string;
|
|
attempts?: number;
|
|
request: { kind: string; params: Record<string, unknown> };
|
|
result?: Record<string, any> | null;
|
|
};
|
|
export function getEnhanceCheckpoint(task: Pick<RecoveryTask, "request" | "result">) {
|
|
const upstream = task.result?.upstreamTask;
|
|
if (
|
|
task.request.kind !== "image-operation" ||
|
|
task.request.params.operation !== "enhance" ||
|
|
upstream?.operation !== "enhance" ||
|
|
typeof upstream.taskId !== "string" ||
|
|
!upstream.taskId.trim() ||
|
|
upstream.sourceImageUrl !== task.request.params.imageUrl
|
|
)
|
|
return null;
|
|
return {
|
|
operation: "enhance" as const,
|
|
taskId: upstream.taskId,
|
|
sourceImageUrl: String(upstream.sourceImageUrl),
|
|
};
|
|
}
|
|
export function hasRecoverableCanvasTask(task: RecoveryTask, now = Date.now()) {
|
|
const created = Date.parse(task.createdAt);
|
|
return (
|
|
Boolean(getEnhanceCheckpoint(task)) &&
|
|
Number.isFinite(created) &&
|
|
now >= created &&
|
|
now - created <= 86400000 &&
|
|
(task.attempts || 0) < 20
|
|
);
|
|
}
|
|
export function canResumeCanvasTask(task: RecoveryTask, now = Date.now()) {
|
|
if (task.status !== "interrupted" || !hasRecoverableCanvasTask(task, now)) return false;
|
|
const updated = Date.parse(task.updatedAt || "");
|
|
const delay = Math.min(300000, 30000 * 2 ** Math.min(4, Math.max(0, (task.attempts || 1) - 1)));
|
|
return Number.isFinite(updated) && now - updated >= delay;
|
|
}
|