random_image_server/
termination.rs1use tokio::signal::unix::signal;
2use tokio::sync::broadcast;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Interrupted {
6 OsSigInt,
7 OsSigQuit,
8 OsSigTerm,
9 UserInt,
10}
11
12#[derive(Debug, Clone)]
13pub struct Terminator {
14 interrupt_tx: broadcast::Sender<Interrupted>,
15}
16
17impl Terminator {
18 #[must_use]
19 pub const fn new(interrupt_tx: broadcast::Sender<Interrupted>) -> Self {
20 Self { interrupt_tx }
21 }
22
23 pub fn terminate(&mut self, interrupted: Interrupted) -> anyhow::Result<()> {
29 self.interrupt_tx.send(interrupted)?;
30
31 Ok(())
32 }
33}
34
35async fn terminate_by_unix_signal(mut terminator: Terminator) {
36 let mut interrupt_signal = signal(tokio::signal::unix::SignalKind::interrupt())
37 .expect("failed to create interrupt signal stream");
38 let mut term_signal = signal(tokio::signal::unix::SignalKind::terminate())
39 .expect("failed to create terminate signal stream");
40 let mut quit_signal = signal(tokio::signal::unix::SignalKind::quit())
41 .expect("failed to create quit signal stream");
42
43 tokio::select! {
44 _ = interrupt_signal.recv() => {
45 terminator
46 .terminate(Interrupted::OsSigInt)
47 .expect("failed to send interrupt signal");
48 }
49 _ = term_signal.recv() => {
50 terminator
51 .terminate(Interrupted::OsSigTerm)
52 .expect("failed to send terminate signal");
53 }
54 _ = quit_signal.recv() => {
55 terminator
56 .terminate(Interrupted::OsSigQuit)
57 .expect("failed to send quit signal");
58 }
59 }
60}
61
62#[allow(clippy::module_name_repetitions)]
64#[must_use]
65pub fn create_termination() -> (Terminator, broadcast::Receiver<Interrupted>) {
66 let (tx, rx) = broadcast::channel(1);
67 let terminator = Terminator::new(tx);
68
69 tokio::spawn(terminate_by_unix_signal(terminator.clone()));
70
71 (terminator, rx)
72}
73
74#[cfg(test)]
75mod test {
76 use std::time::Duration;
77
78 use super::*;
79 use rstest::rstest;
80
81 #[rstest]
82 #[timeout(Duration::from_secs(1))]
83 #[tokio::test]
84 async fn test_terminate() {
85 let (mut terminator, mut rx) = create_termination();
86
87 terminator
88 .terminate(Interrupted::UserInt)
89 .expect("failed to send interrupt signal");
90
91 assert_eq!(rx.recv().await, Ok(Interrupted::UserInt));
92 }
93}