From 6401021364ddd2d83fe693b2124c8b25e682ec2e Mon Sep 17 00:00:00 2001 From: Ben Gauger Date: Thu, 2 Apr 2026 13:06:29 -0600 Subject: [PATCH] fix download retry config and abort handling --- admin/app/jobs/run_download_job.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/admin/app/jobs/run_download_job.ts b/admin/app/jobs/run_download_job.ts index 6813365..a0ee4f9 100644 --- a/admin/app/jobs/run_download_job.ts +++ b/admin/app/jobs/run_download_job.ts @@ -54,6 +54,11 @@ export class RunDownloadJob { totalBytes: 0, } + // Track whether cancellation was explicitly requested by the user (via Redis signal + // or in-process AbortController). BullMQ lock mismatches can also abort the download + // stream, but those should be retried — only user-initiated cancels are unrecoverable. + let userCancelled = false + // Poll Redis for cancel signal every 2s — independent of progress events so cancellation // works even when the stream is stalled and no onProgress ticks are firing. let cancelPollInterval: ReturnType | null = setInterval(async () => { @@ -61,6 +66,7 @@ export class RunDownloadJob { const val = await cancelRedis.get(RunDownloadJob.cancelKey(job.id!)) if (val) { await cancelRedis.del(RunDownloadJob.cancelKey(job.id!)) + userCancelled = true abortController.abort() } } catch { @@ -176,8 +182,9 @@ export class RunDownloadJob { filepath, } } catch (error: any) { - // If this was a cancellation abort, don't let BullMQ retry - if (error?.message?.includes('aborted') || error?.message?.includes('cancelled')) { + // Only prevent retries for user-initiated cancellations. BullMQ lock mismatches + // can also abort the stream, and those should be retried with backoff. + if (userCancelled) { throw new UnrecoverableError(`Download cancelled: ${error.message}`) } throw error