diff --git a/Extensions/Browser b/Extensions/Browser index bd3c7e0..2ee1f37 160000 --- a/Extensions/Browser +++ b/Extensions/Browser @@ -1 +1 @@ -Subproject commit bd3c7e0b4a128d0b4c3b47e2c6b882bc4eee2afa +Subproject commit 2ee1f37921589f52c02007a84d3ee3d49110c89f diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 42a25b6..9bc91a2 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -4598,7 +4598,7 @@ async fn resume_download( return; } if let Some(permit) = permit_candidate { - let _ = queue_manager + let parked = queue_manager .park_aria2_permit_if_missing_for_queue( &id_clone, &queue_id, @@ -4606,6 +4606,14 @@ async fn resume_download( permit, ) .await; + if !parked { + log::warn!( + "aria2 resume [{}]: permit ownership was not established before unpause; leaving gid {} paused", + id_clone, + gid_clone + ); + return; + } } let _ = app_handle_clone.emit( "download-state", diff --git a/src-tauri/src/queue.rs b/src-tauri/src/queue.rs index 243d4a5..87be990 100644 --- a/src-tauri/src/queue.rs +++ b/src-tauri/src/queue.rs @@ -118,6 +118,10 @@ pub enum Aria2RecreateOutcome { Unavailable(String), } +fn aria2_recovery_should_rebuild_after_pause_error(status: &str) -> bool { + status == "removed" +} + /// What kind of sidecar a queued task spawns. Drives which runner the /// dispatcher invokes. #[derive(Debug, Clone)] @@ -2824,6 +2828,16 @@ impl SidecarSpawner for ProductionSpawner { Ok(status) if status == "complete" => { return Ok(Aria2RecreateOutcome::Complete); } + Ok(status) + if aria2_recovery_should_rebuild_after_pause_error(&status) => + { + log::warn!( + "aria2 connection recovery [{}]: gid {} disappeared after forcePause failed; rebuilding from the saved payload: {}", + id, + gid, + error + ); + } Ok(status) => { return Err(format!( "failed to pause aria2 gid {gid} before recreation: {error}; daemon reports {status}" @@ -3128,6 +3142,13 @@ mod tests { ); } + #[test] + fn aria2_recovery_rebuilds_when_force_pause_races_with_removal() { + assert!(aria2_recovery_should_rebuild_after_pause_error("removed")); + assert!(!aria2_recovery_should_rebuild_after_pause_error("paused")); + assert!(!aria2_recovery_should_rebuild_after_pause_error("active")); + } + #[test] fn aria2_connection_options_clamp_untrusted_connection_counts() { let mut options = serde_json::Map::new();