use anyhow::{Context, Result};
use tokio::signal;
pub async fn shutdown_signal() -> Result<()> {
#[cfg(unix)]
{
let mut sigint = signal::unix::signal(signal::unix::SignalKind::interrupt())
.context("Failed to install SIGINT handler")?;
let mut sigterm = signal::unix::signal(signal::unix::SignalKind::terminate())
.context("Failed to install SIGTERM handler")?;
tokio::select! {
_ = sigint.recv() => {
tracing::info!("Received SIGINT signal");
},
_ = sigterm.recv() => {
tracing::info!("Received SIGTERM signal");
},
}
}
#[cfg(not(unix))]
{
signal::ctrl_c()
.await
.context("Failed to install Ctrl+C handler")?;
tracing::info!("Received Ctrl+C signal");
}
Ok(())
}
pub async fn shutdown_signal_handler() {
if let Err(e) = shutdown_signal().await {
tracing::error!("Error setting up shutdown handler: {}", e);
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
use tokio::time::timeout;
#[tokio::test]
#[cfg(unix)]
async fn test_shutdown_signal_with_timeout() {
let result = timeout(Duration::from_millis(100), shutdown_signal()).await;
assert!(result.is_err(), "Should timeout waiting for signal");
}
#[test]
fn test_shutdown_signal_signature() {
let _future = shutdown_signal();
}
}