Stronger kill command (#34)

This commit is contained in:
Louis Knight-Webb
2025-07-01 10:47:28 +01:00
committed by GitHub
parent 1f2075abd3
commit f497f8e676
2 changed files with 63 additions and 2 deletions

View File

@@ -35,6 +35,7 @@ directories = "6.0.0"
open = "5.3.2"
ignore = "0.4"
command-group = { version = "5.0", features = ["with-tokio"] }
nix = { version = "0.29", features = ["signal", "process"] }
openssl-sys = { workspace = true }
rmcp = { version = "0.1.5", features = ["server", "transport-io"] }
schemars = "0.8"

View File

@@ -1,5 +1,10 @@
use std::{collections::HashMap, sync::Arc};
use std::{collections::HashMap, sync::Arc, time::Duration};
#[cfg(unix)]
use nix::{
sys::signal::{kill, Signal},
unistd::Pid,
};
use tokio::sync::Mutex;
use uuid::Uuid;
@@ -96,7 +101,62 @@ impl AppState {
let mut executions = self.running_executions.lock().await;
if let Some(mut execution) = executions.remove(&execution_id) {
// Also kill the direct child process as fallback
// Graceful shutdown sequence: SIGTERM -> SIGKILL -> kill()
let process_id = execution.child.id();
#[cfg(unix)]
{
if let Some(pid) = process_id {
let pid = Pid::from_raw(pid as i32);
// Step 1: Send SIGTERM for graceful shutdown
tracing::info!("Sending SIGTERM to execution process {}", execution_id);
if let Err(e) = kill(pid, Signal::SIGTERM) {
tracing::warn!("Failed to send SIGTERM to process {}: {}", execution_id, e);
} else {
// Wait 2 seconds for graceful shutdown
tokio::time::sleep(Duration::from_secs(2)).await;
// Check if process is still running
if execution
.child
.try_wait()
.is_ok_and(|status| status.is_some())
{
tracing::info!(
"Process {} exited gracefully after SIGTERM",
execution_id
);
return Ok(true);
}
}
// Step 2: Send SIGKILL for forceful termination
tracing::info!("Sending SIGKILL to execution process {}", execution_id);
if let Err(e) = kill(pid, Signal::SIGKILL) {
tracing::warn!("Failed to send SIGKILL to process {}: {}", execution_id, e);
} else {
// Wait 1 second for SIGKILL to take effect
tokio::time::sleep(Duration::from_secs(1)).await;
// Check if process is still running
if execution
.child
.try_wait()
.is_ok_and(|status| status.is_some())
{
tracing::info!("Process {} terminated after SIGKILL", execution_id);
return Ok(true);
}
}
}
}
// Step 3: Fallback to kill() method
tracing::info!(
"Using fallback kill() for execution process {}",
execution_id
);
match execution.child.kill().await {
Ok(_) => {
tracing::info!(