diff --git a/src/workers.rs b/src/workers.rs index b1a32ab..20e6e59 100644 --- a/src/workers.rs +++ b/src/workers.rs @@ -168,13 +168,28 @@ impl Worker { let target = self.target; let task_count = self.task_count; + // Note: we spawn run_inner as a separate task, to prevent it from blocking + // the select below. + let inner = tokio::spawn(Self::run_inner( + graceful_shutdown.clone(), + source, + target, + task_count, + task, + )); + // Dropping a `JoinHandle` detaches the task instead of stopping it, so a + // hard shutdown must abort it explicitly. Otherwise the in-progress copy + // keeps running (and can even commit and report itself as copied) after + // we've told the user we're terminating immediately. + let abort_inner = inner.abort_handle(); + tokio::select! { _ = hard_shutdown.0.cancelled() => { debug!("worker received hard shutdown"); + abort_inner.abort(); Ok(WorkerResult::HardShutdown) }, - // Note: we spawn run_inner as a separate task, to prevent it from blocking this select. - res = tokio::spawn(Self::run_inner(graceful_shutdown.clone(), source, target, task_count, task)) => { + res = inner => { match res { Ok(r) => r, Err(join_error) => { diff --git a/tests/integration/main.rs b/tests/integration/main.rs index 82221cd..1c45c52 100644 --- a/tests/integration/main.rs +++ b/tests/integration/main.rs @@ -1893,11 +1893,6 @@ fn wait_for_message_in_output(output: &mut T, message: &str) -> Result< bail!("message '{message}' not found in output") } -// This test fails under macos, because double ctrl-c does not actually -// hard-stop the program on that platform. Inserting a `yield_now` into the -// tight loop in `copy_from_source_to_sink` fixes the problem, but it needs -// further investigation. -#[cfg(not(target_os = "macos"))] #[test] #[allow(clippy::zombie_processes)] fn double_ctrl_c_stops_hard() -> Result<()> {