Send Signal
Send arbitrary Unix signals to running processes without stopping them.
Overview
The send_signal() and send_signal_label() methods allow sending any Signal to a managed process. Unlike stop(), the process remains in the manager - this is useful for:
- Config reloads - Send
SIGHUPto trigger a reload - Pause/resume - Send
SIGSTOP/SIGCONT - Custom protocols - Send
SIGUSR1/SIGUSR2for application-specific events - Window resize - Send
SIGWINCHto notify terminal applications
sequenceDiagram
participant Consumer
participant Manager as ProcessManager
participant Process
participant OS
Consumer->>Manager: send_signal(id, Signal::Sighup)
Manager->>Process: lookup in DashMap
Process->>OS: kill(pid, SIGHUP)
OS-->>Process: signal delivered
Note over Process: Process stays in DashMap<br/>NOT removed
Manager-->>Consumer: Ok
Example
use process_manager::{ProcessConfig, ProcessManager, ProcessState, Signal, StdioConfig};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let manager = ProcessManager::new();
let config = ProcessConfig::builder()
.command("sleep".to_string())
.args(vec!["30".to_string()])
.stdout(StdioConfig::Null)
.stderr(StdioConfig::Null)
.build();
let id = manager.start("target", &config)?;
println!("Started process with ID {} (PID {})", id, manager.get_pid(id).unwrap());
assert_eq!(manager.is_running(id), Some(true));
assert_eq!(manager.state(id), Some(ProcessState::Running));
// Send SIGWINCH - sleep ignores it, process keeps running
manager.send_signal(id, Signal::Sigwinch)?;
std::thread::sleep(std::time::Duration::from_millis(100));
assert_eq!(manager.is_running(id), Some(true));
assert_eq!(manager.state(id), Some(ProcessState::Running));
println!("After SIGWINCH: still running");
// Send SIGTERM - sleep terminates
manager.send_signal(id, Signal::Sigterm)?;
std::thread::sleep(std::time::Duration::from_millis(200));
assert_eq!(manager.is_running(id), Some(false));
assert_eq!(manager.state(id), Some(ProcessState::Crashed));
println!("After SIGTERM: process exited");
manager.stop(id)?;
println!("Manager empty: {}", manager.is_empty());
Ok(())
}
Label-based Signaling
Send a signal to all processes sharing a label:
#![allow(unused)]
fn main() {
use process_manager::{ProcessConfig, ProcessManager, Signal, StdioConfig};
let manager = ProcessManager::new();
let config = ProcessConfig::builder()
.command("my-worker".to_string())
.stdout(StdioConfig::Null)
.stderr(StdioConfig::Null)
.build();
// Start a pool of 4 workers
for _ in 0..4 {
manager.start("worker-pool", &config)?;
}
// Send SIGHUP to all workers to trigger a config reload
manager.send_signal_label("worker-pool", Signal::Sighup)?;
}
Running the Example
cargo run --example send_signal