Skip to main content

mecha10_runtime/
shutdown.rs

1//! Graceful shutdown handling
2
3use tokio::sync::broadcast;
4
5#[derive(Clone)]
6pub struct ShutdownHandle {
7    tx: broadcast::Sender<()>,
8}
9
10impl ShutdownHandle {
11    /// Create a new shutdown handle
12    pub fn new() -> Self {
13        let (tx, _) = broadcast::channel(1);
14        Self { tx }
15    }
16
17    /// Trigger shutdown
18    pub fn shutdown(&self) {
19        let _ = self.tx.send(());
20    }
21
22    /// Wait for shutdown signal
23    pub async fn wait_shutdown(&self) {
24        let mut rx = self.tx.subscribe();
25        let _ = rx.recv().await;
26    }
27
28    /// Subscribe to shutdown signals
29    pub fn subscribe(&self) -> broadcast::Receiver<()> {
30        self.tx.subscribe()
31    }
32}
33
34impl Default for ShutdownHandle {
35    fn default() -> Self {
36        Self::new()
37    }
38}
39
40/// Wait for Ctrl+C signal
41pub async fn wait_for_signal() {
42    #[cfg(unix)]
43    {
44        use tokio::signal::unix::{signal, SignalKind};
45        let mut sigterm = signal(SignalKind::terminate()).expect("Failed to setup SIGTERM handler");
46        let mut sigint = signal(SignalKind::interrupt()).expect("Failed to setup SIGINT handler");
47
48        tokio::select! {
49            _ = sigterm.recv() => {
50                tracing::info!("Received SIGTERM, shutting down gracefully");
51            }
52            _ = sigint.recv() => {
53                tracing::info!("Received SIGINT, shutting down gracefully");
54            }
55        }
56    }
57
58    #[cfg(not(unix))]
59    {
60        tokio::signal::ctrl_c().await.expect("Failed to listen for Ctrl+C");
61        tracing::info!("Received Ctrl+C, shutting down gracefully");
62    }
63}