faucet_server/
shutdown.rs1use std::sync::atomic::{AtomicBool, Ordering};
2
3use tokio::sync::Notify;
4
5use crate::leak;
6
7const WAIT_STOP_PRINT: std::time::Duration = std::time::Duration::from_secs(5);
8
9pub struct ShutdownSignal {
10 is_shutdown: AtomicBool,
11 notify: Notify,
12}
13
14impl Default for ShutdownSignal {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl ShutdownSignal {
21 pub fn new() -> Self {
22 ShutdownSignal {
23 is_shutdown: AtomicBool::new(false),
24 notify: Notify::new(),
25 }
26 }
27
28 pub fn shutdown(&self) {
29 self.is_shutdown.store(true, Ordering::Relaxed);
30 self.notify.notify_waiters();
31 }
32
33 pub async fn wait(&self) {
34 if self.is_shutdown.load(Ordering::Relaxed) {
35 return;
36 }
37 self.notify.notified().await;
39 }
40}
41
42pub fn graceful() -> &'static ShutdownSignal {
43 use crate::global_conn::current_connections;
44
45 let signal = leak!(ShutdownSignal::new()) as &'static ShutdownSignal;
46
47 {
48 ctrlc::set_handler(move || {
49 log::info!(target: "faucet", "Received stop signal, waiting for all users to disconnect");
50 let mut last_5_sec = std::time::Instant::now();
51 while current_connections() > 0 {
52 std::thread::yield_now();
53 if last_5_sec.elapsed() > WAIT_STOP_PRINT {
54 log::info!(
55 target: "faucet",
56 "Active connections = {}, waiting for all connections to stop.",
57 current_connections()
58 );
59 last_5_sec = std::time::Instant::now();
60 }
61 }
62 signal.shutdown();
63 })
64 .expect("Unable to set term handler. This is a bug");
65 }
66
67 signal
68}
69
70pub fn immediate() -> &'static ShutdownSignal {
71 let signal = leak!(ShutdownSignal::new()) as &'static ShutdownSignal;
72 {
73 ctrlc::set_handler(move || {
74 log::info!(target: "faucet", "Starting immediate shutdown handle");
75 signal.shutdown()
76 })
77 .expect("Unable to set term handler. This is a bug");
78 }
79 signal
80}