ref:main
//! Shutdown signal handling for the runner.
//!
//! Listens for SIGINT (Ctrl+C) and SIGTERM (`systemctl stop`, `kill`,
//! `docker stop`, k8s pre-SIGKILL) — both trigger graceful drain via the
//! shared `Notify`. SIGHUP and SIGPIPE are explicitly ignored so the
//! default actions (terminate / write-error-kills-process) don't kill us.
//!
//! On Unix we use `tokio::signal::unix::signal`. On non-Unix we fall back
//! to ctrl_c only.
use std::sync::Arc;
use tokio::sync::Notify;
/// Spawn the signal listener. The returned `Notify` fires once on the
/// first SIGINT or SIGTERM; subsequent signals are absorbed silently so
/// repeated Ctrl+C doesn't accidentally interrupt the drain logic.
pub fn install() -> Arc<Notify> {
let shutdown = Arc::new(Notify::new());
let trigger = shutdown.clone();
tokio::spawn(async move {
wait_for_signal().await;
trigger.notify_waiters();
});
shutdown
}
#[cfg(unix)]
async fn wait_for_signal() {
use tokio::signal::unix::{signal, SignalKind};
let mut sigint = signal(SignalKind::interrupt()).expect("failed to install SIGINT handler");
let mut sigterm = signal(SignalKind::terminate()).expect("failed to install SIGTERM handler");
// Explicitly absorb SIGHUP (default action: terminate) and SIGPIPE
// (default action: terminate on broken stdout/stderr pipe) so a
// dropped terminal or a broken log pipe doesn't kill the runner.
let mut sighup = signal(SignalKind::hangup()).expect("failed to install SIGHUP handler");
let mut sigpipe = signal(SignalKind::pipe()).expect("failed to install SIGPIPE handler");
tokio::spawn(async move {
loop {
sighup.recv().await;
eprintln!("(SIGHUP ignored)");
}
});
tokio::spawn(async move {
loop {
sigpipe.recv().await;
// Don't log SIGPIPE — they're high-volume on broken stdout.
}
});
tokio::select! {
_ = sigint.recv() => eprintln!("\nReceived SIGINT, shutting down..."),
_ = sigterm.recv() => eprintln!("Received SIGTERM, shutting down..."),
}
}
#[cfg(not(unix))]
async fn wait_for_signal() {
let _ = tokio::signal::ctrl_c().await;
eprintln!("Received Ctrl+C, shutting down...");
}