fix(queue): preserve lifecycle ownership during recovery

Require queue-permit ownership before resuming a paused GID and rebuild a job when its GID disappears during recovery.

Advance the Browser companion with the automatic-capture handoff guard for #28.
This commit is contained in:
NimBold
2026-07-26 18:10:04 +03:30
parent 7787f4e6c0
commit 240055497d
3 changed files with 31 additions and 2 deletions
+9 -1
View File
@@ -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",
+21
View File
@@ -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();