From bfdf21d9787e54f524be3ff4f616ac8c812cbb5e Mon Sep 17 00:00:00 2001 From: Osamaali313 Date: Wed, 5 Aug 2026 22:25:41 +0300 Subject: [PATCH] fix(content): re-download content updates after a failed attempt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- .../app/services/collection_update_service.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/admin/app/services/collection_update_service.ts b/admin/app/services/collection_update_service.ts index 5ae7521..df6d5bb 100644 --- a/admin/app/services/collection_update_service.ts +++ b/admin/app/services/collection_update_service.ts @@ -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}`, } }