From a02d43582ae130d6a575c82bd3b5e3902fb58842 Mon Sep 17 00:00:00 2001 From: Ben Gauger Date: Thu, 2 Apr 2026 15:19:59 -0600 Subject: [PATCH] use abort reason to detect user-initiated cancels --- admin/app/jobs/run_download_job.ts | 5 +++-- admin/app/services/download_service.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/admin/app/jobs/run_download_job.ts b/admin/app/jobs/run_download_job.ts index a0ee4f9..12b3532 100644 --- a/admin/app/jobs/run_download_job.ts +++ b/admin/app/jobs/run_download_job.ts @@ -67,7 +67,7 @@ export class RunDownloadJob { if (val) { await cancelRedis.del(RunDownloadJob.cancelKey(job.id!)) userCancelled = true - abortController.abort() + abortController.abort('user-cancel') } } catch { // Redis errors are non-fatal; in-process AbortController covers same-process cancels @@ -184,7 +184,8 @@ export class RunDownloadJob { } catch (error: any) { // Only prevent retries for user-initiated cancellations. BullMQ lock mismatches // can also abort the stream, and those should be retried with backoff. - if (userCancelled) { + // Check both the flag (Redis poll) and abort reason (in-process cancel). + if (userCancelled || abortController.signal.reason === 'user-cancel') { throw new UnrecoverableError(`Download cancelled: ${error.message}`) } throw error diff --git a/admin/app/services/download_service.ts b/admin/app/services/download_service.ts index 40cdca3..ac9d02d 100644 --- a/admin/app/services/download_service.ts +++ b/admin/app/services/download_service.ts @@ -125,7 +125,7 @@ export class DownloadService { await RunDownloadJob.signalCancel(jobId) // Also try in-memory abort (works if worker is in same process) - RunDownloadJob.abortControllers.get(jobId)?.abort() + RunDownloadJob.abortControllers.get(jobId)?.abort('user-cancel') RunDownloadJob.abortControllers.delete(jobId) // Poll for terminal state (up to 4s at 250ms intervals) — cooperates with BullMQ's lifecycle