Skip to main content

mecha10_runtime/
shutdown.rs

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