modkit/runtime/
shutdown.rs1use anyhow::Result;
2
3pub async fn wait_for_shutdown() -> Result<()> {
8 #[cfg(unix)]
9 {
10 use tokio::signal::unix::{SignalKind, signal};
11 let mut sigterm = signal(SignalKind::terminate())?;
12 let mut sigint = signal(SignalKind::interrupt())?; tokio::select! {
14 _ = sigterm.recv() => {},
15 _ = sigint.recv() => {},
16 _ = tokio::signal::ctrl_c() => {}, }
18 Ok(())
19 }
20
21 #[cfg(windows)]
22 {
23 use tokio::signal::windows::{ctrl_break, ctrl_c, ctrl_close, ctrl_logoff, ctrl_shutdown};
24 use tokio::time::{Duration, timeout};
25
26 async fn arm_once() -> std::io::Result<()> {
27 let mut c = ctrl_c()?;
29 let mut br = ctrl_break()?;
30 let mut cl = ctrl_close()?;
31 let mut lo = ctrl_logoff()?;
32 let mut sh = ctrl_shutdown()?;
33
34 tokio::select! {
35 _ = c.recv() => {},
36 _ = br.recv() => {},
37 _ = cl.recv() => {},
38 _ = lo.recv() => {},
39 _ = sh.recv() => {},
40 }
41 Ok(())
42 }
43
44 match timeout(Duration::from_millis(50), arm_once()).await {
46 Ok(Ok(())) => {
47 tracing::warn!("shutdown: early Windows console signal detected; debouncing");
48 arm_once().await?; }
50 Ok(Err(e)) => return Err(e.into()),
51 Err(_elapsed) => {
52 arm_once().await?;
54 }
55 }
56 Ok(())
57 }
58}