fix(content): re-download content updates after a failed attempt

applyUpdate guarded with the raw RunDownloadJob.getByUrl and only bailed
out for active/waiting/delayed states, letting failed/completed states
fall through to dispatch. But dispatch adds the job under a deterministic
jobId (sha256 of the URL) with no removeOnFail, so once a download
exhausts its retries the failed job persists in Redis. The next apply
then hits "job already exists", dispatch returns the stale failed job,
and applyUpdate reports success while nothing is re-downloaded — the
resource is stuck forever.

Use getActiveByUrl instead, which removes any terminal job for the URL
before returning, so a fresh job is dispatched. This matches every other
dispatch site (map_service, zim_service, creator_pack_service).
This commit is contained in:
Osamaali313 2026-08-05 22:25:41 +03:00
parent b6c6ff4f30
commit bfdf21d978
1 changed files with 12 additions and 8 deletions

View File

@ -99,15 +99,19 @@ export class CollectionUpdateService {
update: ResourceUpdateInfo,
options?: { auto?: boolean }
): Promise<{ success: boolean; jobId?: string; error?: string }> {
// Check if a download is already in progress for this URL
const existingJob = await RunDownloadJob.getByUrl(update.download_url)
// Only block when a download is genuinely in progress. getActiveByUrl
// removes any terminal (failed/completed) job for this URL first, so a
// previous failed attempt doesn't leave a stale job that blocks the
// re-dispatch below. Using the raw getByUrl here (unlike every other
// dispatch site) meant a failed download stuck the resource forever: the
// failed job survived under the deterministic jobId, dispatch hit "job
// already exists" and returned it, and applyUpdate reported success while
// nothing was re-downloaded.
const existingJob = await RunDownloadJob.getActiveByUrl(update.download_url)
if (existingJob) {
const state = await existingJob.getState()
if (state === 'active' || state === 'waiting' || state === 'delayed') {
return {
success: false,
error: `A download is already in progress for ${update.resource_id}`,
}
return {
success: false,
error: `A download is already in progress for ${update.resource_id}`,
}
}