static_web_server/
signals.rs1use std::sync::Arc;
10use tokio::sync::{watch::Receiver, Mutex};
11use tokio::time::{sleep, Duration};
12
13#[cfg(unix)]
14use {
15 crate::Result, futures_util::stream::StreamExt, signal_hook::consts::signal::*,
16 signal_hook_tokio::Signals,
17};
18
19#[cfg(unix)]
20#[cfg_attr(docsrs, doc(cfg(unix)))]
21#[inline]
22pub fn create_signals() -> Result<Signals> {
24 Ok(Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT])?)
25}
26
27#[cfg(unix)]
28pub async fn wait_for_signals(
30 signals: Signals,
31 grace_period_secs: u8,
32 cancel_recv: Arc<Mutex<Option<Receiver<()>>>>,
33) {
34 let (first_tx, mut base_rx) = tokio::sync::mpsc::channel(1);
35 let last_tx = first_tx.clone();
36
37 tokio::spawn(async move {
38 let mut signals = signals.fuse();
39 while let Some(signal) = signals.next().await {
40 match signal {
41 SIGHUP => {
42 tracing::debug!("SIGHUP caught, nothing to do about")
44 }
45 SIGTERM | SIGINT | SIGQUIT => {
46 tracing::info!("SIGTERM, SIGINT or SIGQUIT signal caught");
47 first_tx.send(()).await.ok();
48 break;
49 }
50 _ => unreachable!(),
51 }
52 }
53 });
54
55 tokio::spawn(async move {
56 if let Some(recv) = &mut *cancel_recv.lock().await {
57 recv.changed().await.ok();
58 last_tx.send(()).await.ok();
59 tracing::info!("signals interrupted manually by cancel_recv");
60 }
61 });
62
63 base_rx.recv().await.take();
64
65 delay_graceful_shutdown(grace_period_secs).await;
67 tracing::info!("delegating server's graceful shutdown");
68}
69
70async fn delay_graceful_shutdown(grace_period_secs: u8) {
72 if grace_period_secs > 0 {
73 tracing::info!(
74 "grace period of {}s after the SIGTERM started",
75 grace_period_secs
76 );
77 sleep(Duration::from_secs(grace_period_secs.into())).await;
78 tracing::info!("grace period has elapsed");
79 }
80}
81
82#[cfg(windows)]
83#[cfg_attr(docsrs, doc(cfg(windows)))]
84pub async fn wait_for_ctrl_c(cancel_recv: Arc<Mutex<Option<Receiver<()>>>>, grace_period_secs: u8) {
86 if let Some(receiver) = &mut *cancel_recv.lock().await {
87 receiver.changed().await.ok();
88 }
89
90 delay_graceful_shutdown(grace_period_secs).await;
91 tracing::info!("delegating server's graceful shutdown");
92}