From 2ceff6955c6708f1f40f3a183bb5bf642f16d5d3 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 18 Jun 2025 14:00:52 +0200 Subject: [PATCH] Make session kill endpoint wait for process death MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DELETE endpoint now waits up to 3 seconds for process to actually die - Polls every 100ms to confirm process termination after SIGKILL - Returns different messages based on whether process confirmed dead - Makes is_pid_alive function public for reuse - Provides more reliable session killing with proper status updates 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- tty-fwd/src/api_server.rs | 33 +++++++++++++++++++++++++++------ tty-fwd/src/sessions.rs | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/tty-fwd/src/api_server.rs b/tty-fwd/src/api_server.rs index 77e61675..cfdfc6de 100644 --- a/tty-fwd/src/api_server.rs +++ b/tty-fwd/src/api_server.rs @@ -1035,13 +1035,30 @@ fn handle_session_kill(control_path: &Path, path: &str) -> Response { return json_response(StatusCode::OK, &response); } - // Try SIGKILL first, then SIGKILL if needed + // Try SIGKILL and wait for process to actually die let (status, message) = match sessions::send_signal_to_session(control_path, &session_id, 9) { Ok(()) => { - // Update session status to exited after killing the process + // Wait up to 3 seconds for the process to actually die let session_path = control_path.join(&session_id); let session_json_path = session_path.join("session.json"); - + + let mut process_died = false; + if let Ok(content) = std::fs::read_to_string(&session_json_path) { + if let Ok(session_info) = serde_json::from_str::(&content) { + if let Some(pid) = session_info.get("pid").and_then(|p| p.as_u64()) { + // Wait for the process to actually die + for _ in 0..30 { // 30 * 100ms = 3 seconds max + if !sessions::is_pid_alive(pid as u32) { + process_died = true; + break; + } + std::thread::sleep(std::time::Duration::from_millis(100)); + } + } + } + } + + // Update session status to exited after confirming kill if let Ok(content) = std::fs::read_to_string(&session_json_path) { if let Ok(mut session_info) = serde_json::from_str::(&content) { session_info["status"] = serde_json::json!("exited"); @@ -1051,9 +1068,13 @@ fn handle_session_kill(control_path: &Path, path: &str) -> Response { } } } - - (StatusCode::OK, "Session killed") - } + + if process_died { + (StatusCode::OK, "Session killed") + } else { + (StatusCode::OK, "Session kill signal sent (process may still be terminating)") + } + }, Err(e) => { let response = ApiResponse { success: None, diff --git a/tty-fwd/src/sessions.rs b/tty-fwd/src/sessions.rs index cd266372..ac7f81f6 100644 --- a/tty-fwd/src/sessions.rs +++ b/tty-fwd/src/sessions.rs @@ -249,7 +249,7 @@ fn write_to_pipe_with_timeout( Ok(()) } -fn is_pid_alive(pid: u32) -> bool { +pub fn is_pid_alive(pid: u32) -> bool { let output = Command::new("ps").arg("-p").arg(pid.to_string()).output(); match output {