diff options
| author | soryu <soryu@soryu.co> | 2026-01-26 22:41:18 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-26 22:41:30 +0000 |
| commit | de1eb0a923f6c5b768ac49f0425b7213a89301b7 (patch) | |
| tree | 410e886a638f91bc9d0e9bc7b6a6f1beead4e818 /makima/src/daemon/task/manager.rs | |
| parent | d1f5dadb549d499c5aeee9cacf6c9aa0a233c198 (diff) | |
| download | soryu-de1eb0a923f6c5b768ac49f0425b7213a89301b7.tar.gz soryu-de1eb0a923f6c5b768ac49f0425b7213a89301b7.zip | |
Terminate all processes on makima CLI SIGTERM
Diffstat (limited to 'makima/src/daemon/task/manager.rs')
| -rw-r--r-- | makima/src/daemon/task/manager.rs | 29 |
1 files changed, 15 insertions, 14 deletions
diff --git a/makima/src/daemon/task/manager.rs b/makima/src/daemon/task/manager.rs index bbcf661..b162f33 100644 --- a/makima/src/daemon/task/manager.rs +++ b/makima/src/daemon/task/manager.rs @@ -1412,13 +1412,14 @@ impl TaskManager { Ok(concurrency_key) } - /// Gracefully shutdown all running Claude processes. + /// Gracefully shutdown all running Claude processes and their children. /// - /// This sends SIGTERM to all active processes, waits for them to exit gracefully, + /// This sends SIGTERM to all active process groups, waits for them to exit gracefully, /// and then sends SIGKILL to any that don't exit within the timeout. + /// Uses process groups to ensure all child processes (bash commands, etc.) are also killed. #[cfg(unix)] pub async fn shutdown_all_processes(&self, timeout: std::time::Duration) { - use nix::sys::signal::{kill, Signal}; + use nix::sys::signal::{killpg, Signal}; use nix::unistd::Pid; let pids: Vec<(Uuid, u32)> = { @@ -1431,19 +1432,19 @@ impl TaskManager { return; } - tracing::info!(count = pids.len(), "Sending SIGTERM to all Claude processes"); + tracing::info!(count = pids.len(), "Sending SIGTERM to all Claude process groups"); - // Send SIGTERM to all processes + // Send SIGTERM to all process groups (each Claude process is its own group leader) for (task_id, pid) in &pids { - match kill(Pid::from_raw(*pid as i32), Signal::SIGTERM) { + match killpg(Pid::from_raw(*pid as i32), Signal::SIGTERM) { Ok(()) => { - tracing::debug!(task_id = %task_id, pid = pid, "Sent SIGTERM to process"); + tracing::debug!(task_id = %task_id, pid = pid, "Sent SIGTERM to process group"); } Err(nix::errno::Errno::ESRCH) => { - tracing::debug!(task_id = %task_id, pid = pid, "Process already exited"); + tracing::debug!(task_id = %task_id, pid = pid, "Process group already exited"); } Err(e) => { - tracing::warn!(task_id = %task_id, pid = pid, error = %e, "Failed to send SIGTERM"); + tracing::warn!(task_id = %task_id, pid = pid, error = %e, "Failed to send SIGTERM to process group"); } } } @@ -1466,7 +1467,7 @@ impl TaskManager { tokio::time::sleep(check_interval).await; } - // Send SIGKILL to any remaining processes + // Send SIGKILL to any remaining process groups let remaining: Vec<(Uuid, u32)> = { let guard = self.active_pids.read().await; guard.iter().map(|(k, v)| (*k, *v)).collect() @@ -1475,15 +1476,15 @@ impl TaskManager { if !remaining.is_empty() { tracing::warn!( count = remaining.len(), - "Some processes did not exit gracefully, sending SIGKILL" + "Some process groups did not exit gracefully, sending SIGKILL" ); for (task_id, pid) in &remaining { - match kill(Pid::from_raw(*pid as i32), Signal::SIGKILL) { + match killpg(Pid::from_raw(*pid as i32), Signal::SIGKILL) { Ok(()) => { - tracing::debug!(task_id = %task_id, pid = pid, "Sent SIGKILL to process"); + tracing::debug!(task_id = %task_id, pid = pid, "Sent SIGKILL to process group"); } Err(e) => { - tracing::warn!(task_id = %task_id, pid = pid, error = %e, "Failed to send SIGKILL"); + tracing::warn!(task_id = %task_id, pid = pid, error = %e, "Failed to send SIGKILL to process group"); } } } |
