Skip to main content

max / makenotwork

ops-exec: kill_on_drop the rsync transport so a cancelled deploy can't orphan it run_rsync built its Command without kill_on_drop, unlike the ssh-exec (remote.rs) and local-exec (executor.rs) paths. When a Sando promote's HTTP handler was cancelled by a client disconnect, the rsync it had spawned kept running; a retry then started a second rsync that fought the first over the same --delete destination dir, throttling both and wedging the deploy (hit live during the 0.10.12 testnot promote). Setting kill_on_drop at the single rsync construction point tears the transfer down when the caller's future is dropped, so a cancelled promote aborts cleanly and a retry runs unobstructed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-08 23:18 UTC
Commit: 9ee146be728d36f34dac147907342e7a4d92a035
Parent: b1546dc
1 file changed, +7 insertions, -0 deletions
@@ -67,6 +67,13 @@ fn validate_env_names(step: &Step) -> Result<()> {
67 67 /// is either a plain path (local) or `target:path` (ssh).
68 68 fn rsync_command(src: &str, dst: &str, over_ssh: bool, opts: &SyncOpts) -> Command {
69 69 let mut rsync = Command::new("rsync");
70 + // Kill the transfer if the caller's future is dropped (e.g. a promote whose
71 + // HTTP handler was cancelled by a client disconnect). Without this the
72 + // rsync orphans and keeps running; a retry then spawns a second rsync that
73 + // fights the first over the same `--delete` destination dir, wedging the
74 + // deploy. Matches the ssh-exec (remote.rs) and local-exec (executor.rs)
75 + // paths, which already set it.
76 + rsync.kill_on_drop(true);
70 77 rsync.arg("-az").arg("--partial");
71 78 if opts.delete {
72 79 rsync.arg("--delete");