Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Stop Escalation

Observe the SIGTERM → SIGKILL escalation path with a short timeout.

Overview

When stop() is called, the manager sends the configured kill_signal (default SIGTERM), waits up to terminate_timeout_ms, and escalates to SIGKILL if the process is still running. This example uses a very short timeout (100ms) and a process that ignores SIGTERM to demonstrate the escalation.

sequenceDiagram
    participant Consumer
    participant Manager as ProcessManager
    participant Process
    participant OS

    Consumer->>Manager: stop(id)
    Manager->>OS: kill(pid, SIGTERM)
    Note over Process: Process ignores SIGTERM<br/>(trap '' TERM)
    Manager->>Manager: wait 100ms<br/>(terminate_timeout_ms)
    Note over Manager: Process still running
    Manager->>OS: kill(pid, SIGKILL)
    Note over Process: SIGKILL cannot be caught
    Process-->>Manager: killed
    Manager->>Manager: join_readers
    Manager-->>Consumer: Ok

Example

use process_manager::{KillSignal, ProcessConfig, ProcessManager, StdioConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let manager = ProcessManager::new();

    // Process that ignores SIGTERM (trap '' TERM)
    let config = ProcessConfig::builder()
        .command("sh".to_string())
        .args(vec!["-c".to_string(), "trap '' TERM; sleep 30".to_string()])
        .kill_signal(KillSignal::Sigterm)
        .terminate_timeout_ms(100)
        .stdout(StdioConfig::Null)
        .stderr(StdioConfig::Null)
        .build();

    let id = manager.start("stubborn", &config)?;
    println!("Started stubborn process (PID {})", manager.get_pid(id).unwrap());

    // stop() will send SIGTERM, wait 100ms, then escalate to SIGKILL
    manager.stop(id)?;
    println!("Process stopped (escalated to SIGKILL)");
    assert!(manager.is_empty());

    Ok(())
}

Running the Example

cargo run --example stop_escalation