From 90cf37c471ce531b90aabb048ceaca25996da2cf Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Tue, 10 Feb 2026 21:07:25 +0100 Subject: [PATCH] node: On Windows, use job for upload-pack child Reports of zombie (grand)child processes were received. By associating the `git upload-pack` process with a job, zombies are prevented. --- CHANGELOG.md | 2 ++ Cargo.lock | 1 + crates/radicle-node/Cargo.toml | 1 + crates/radicle-node/src/worker/upload_pack.rs | 11 +++++++++-- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5728f96a..96fe6e6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 but marks an escape sequence on Unix-like systems), which lead to issues when attempting to execute child processes. This is fixed by using `winsplit` on Windows instead. +- On Windows, zombie `git-upload-pack` processes are now prevented by using the + "Job" API of the operating system to group child processes and their children. ## Deprecations diff --git a/Cargo.lock b/Cargo.lock index 7862ec24..d39168c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3060,6 +3060,7 @@ dependencies = [ "radicle-protocol", "radicle-signals", "radicle-systemd", + "radicle-windows", "scrypt", "serde", "serde_json", diff --git a/crates/radicle-node/Cargo.toml b/crates/radicle-node/Cargo.toml index 1ff3e213..b49bb904 100644 --- a/crates/radicle-node/Cargo.toml +++ b/crates/radicle-node/Cargo.toml @@ -48,6 +48,7 @@ radicle-systemd = { workspace = true, optional = true } [target.'cfg(windows)'.dependencies] winpipe = { workspace = true } +radicle-windows = { workspace = true } [dev-dependencies] mio = { version = "1", features = ["os-ext"] } diff --git a/crates/radicle-node/src/worker/upload_pack.rs b/crates/radicle-node/src/worker/upload_pack.rs index e84206ba..d36b30ff 100644 --- a/crates/radicle-node/src/worker/upload_pack.rs +++ b/crates/radicle-node/src/worker/upload_pack.rs @@ -84,6 +84,9 @@ where cmd.spawn()? }; + #[cfg(windows)] + let job = radicle_windows::jobs::Job::for_child(&child)?; + let mut stdin = child.stdin.take().unwrap(); let mut stdout = io::BufReader::new(child.stdout.take().unwrap()); let reporter = std::sync::Mutex::new(Reporter::new(header.repo, remote, emitter.clone(), send)); @@ -150,8 +153,12 @@ where if let Err(e) = reader.join() { log::warn!(target: "worker", "Upload pack thread panicked: {e:?}"); } - child.kill()?; - Ok::<_, io::Error>(()) + + #[cfg(unix)] + return child.kill(); + + #[cfg(windows)] + return job.terminate(3); })?; let status = child.wait()?;