1use crate::handler::BoxFuture;
4use crate::state::StateMap;
5use std::sync::Arc;
6use tokio::sync::watch;
7
8#[derive(Clone, Debug)]
13pub struct Shutdown {
14 inner: watch::Receiver<bool>,
15}
16
17impl Shutdown {
18 pub(crate) fn new(inner: watch::Receiver<bool>) -> Self {
19 Self { inner }
20 }
21
22 pub fn is_triggered(&self) -> bool {
24 *self.inner.borrow()
25 }
26
27 pub async fn recv(&mut self) {
29 loop {
30 if *self.inner.borrow() {
31 return;
32 }
33 if self.inner.changed().await.is_err() {
34 return;
35 }
36 }
37 }
38}
39
40#[cfg(any(test, feature = "testing"))]
42#[derive(Clone, Debug)]
43pub struct ShutdownSender(watch::Sender<bool>);
44
45#[cfg(any(test, feature = "testing"))]
46#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
47#[allow(dead_code)]
48#[must_use]
49pub fn shutdown_channel() -> (ShutdownSender, Shutdown) {
50 let (tx, rx) = watch::channel(false);
51 (ShutdownSender(tx), Shutdown::new(rx))
52}
53
54#[cfg(any(test, feature = "testing"))]
55impl ShutdownSender {
56 pub fn send(&self, value: bool) -> bool {
57 self.0.send(value).is_ok()
58 }
59}
60
61pub trait BackgroundService: Send {
66 fn name(&self) -> &str;
67
68 fn run(
70 self: Box<Self>,
71 state: Arc<StateMap>,
72 shutdown: Shutdown,
73 ) -> BoxFuture<()>;
74}
75
76pub(crate) type BoxedService = Box<dyn BackgroundService>;
78
79pub async fn wait_shutdown(mut shutdown: Shutdown) {
81 shutdown.recv().await
82}