From be2a98fbcd3eef4d31f3e5a7e2c5d45b4dd48dc6 Mon Sep 17 00:00:00 2001 From: NimBold Date: Mon, 13 Jul 2026 04:08:18 +0330 Subject: [PATCH] fix(downloads): reconcile completed aria2 pause requests --- src-tauri/src/lib.rs | 16 ++++++++++++++++ src-tauri/src/queue.rs | 10 ++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a735663..fb3b33d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3272,6 +3272,22 @@ async fn pause_download( ensure_aria2_gid_result("forcePause", gid, &result)?; log::info!("aria2 pause [{}]: gid {} paused", id, gid); } + "complete" => { + // Aria2 can reach complete before its terminal event updates + // Firelink's row. Treat a pause request in that narrow window + // as an idempotent completion reconciliation, not as an + // actionable pause failure. + log::info!( + "aria2 pause [{}]: gid {} was already complete; reconciling completion", + id, + gid + ); + state + .queue_manager + .apply_completion_locked(&id, crate::queue::PendingOutcome::Complete) + .await; + return Ok(()); + } terminal => { let retrying = state.queue_manager.has_aria2_retry_state(&id).await; state.queue_manager.clear_aria2_retry_state(&id).await; diff --git a/src-tauri/src/queue.rs b/src-tauri/src/queue.rs index f33502d..88f09e5 100644 --- a/src-tauri/src/queue.rs +++ b/src-tauri/src/queue.rs @@ -774,10 +774,12 @@ impl QueueManager { self.apply_completion_locked(id, outcome).await; } - /// Apply a completion while the caller owns the download control lock. - /// Keeping the epoch transition and terminal cleanup under that lock - /// prevents an old WebSocket event from completing a newer lifecycle. - async fn apply_completion_locked(&self, id: &str, outcome: PendingOutcome) { + /// Apply a terminal outcome while the caller owns the download control + /// lock. Keeping the epoch transition and terminal cleanup under that + /// lock prevents an old WebSocket event from completing a newer lifecycle + /// and lets commands reconcile an Aria2 terminal status without releasing + /// the lock first. + pub(crate) async fn apply_completion_locked(&self, id: &str, outcome: PendingOutcome) { // A terminal event invalidates every delayed retry or control worker // from the previous lifecycle before releasing its permit. self.next_aria2_control_epoch(id).await;