Retain exact recovery after batch start failure

Persist job-ID terminal outcomes before final queue acknowledgement and clear recovery evidence only after both the terminal marker and renderer queue are durable.
This commit is contained in:
Sucukdeluxe
2026-08-13 21:16:04 +02:00
parent a7fb3421f1
commit 746ae29a4f
3 changed files with 78 additions and 14 deletions
+34 -1
View File
@@ -31,6 +31,39 @@
return Array.from(snapshots.values());
}
function buildFailedUploadSummary(tasks, message, now = Date.now()) {
const files = new Map();
for (const [index, task] of (Array.isArray(tasks) ? tasks : []).entries()) {
if (!task || typeof task !== 'object') continue;
const filePath = typeof task.file === 'string' ? task.file : '';
const fileName = filePath.split(/[\\/]/).pop() || `upload-${index + 1}`;
const key = filePath || `${fileName}\0${index}`;
if (!files.has(key)) files.set(key, { name: fileName, size: 0, results: [] });
files.get(key).results.push({
jobId: typeof task.jobId === 'string' ? task.jobId : '',
hoster: typeof task.hoster === 'string' ? task.hoster : '',
status: 'error',
error: message,
failureDetails: null,
download_url: null,
embed_url: null,
file_code: null
});
}
const grouped = Array.from(files.values());
const failed = grouped.reduce((count, file) => count + file.results.length, 0);
return {
id: `start-error-${now}`,
timestamp: new Date(now).toISOString(),
total: failed,
succeeded: 0,
failed,
skipped: 0,
files: grouped,
error: message
};
}
function getRecoveryOutcome(job, recovery) {
const status = typeof job?.status === 'string' ? job.status : 'preview';
const jobId = typeof job?.id === 'string' ? job.id : '';
@@ -50,5 +83,5 @@
return { status, interrupted: interruptedIds.has(jobId) && !terminalStatuses.has(status) };
}
return { buildTerminalJobSnapshots, getRecoveryOutcome };
return { buildFailedUploadSummary, buildTerminalJobSnapshots, getRecoveryOutcome };
});