Skip to main content

hatchery_server/
supervisor.rs

1//! Lifecycle: start the autostart subservices, answer health, stop everything.
2
3use crate::error::ServerError;
4use crate::subservice::{Status, Subservice};
5use std::sync::{Arc, Mutex};
6
7#[derive(Clone)]
8pub struct Supervisor {
9    inner: Arc<Mutex<Vec<Box<dyn Subservice>>>>,
10}
11
12impl Supervisor {
13    pub fn new(subservices: Vec<Box<dyn Subservice>>) -> Self {
14        Self { inner: Arc::new(Mutex::new(subservices)) }
15    }
16
17    /// Start every subservice that is not on-demand. A failure is reported and
18    /// does not stop its siblings.
19    pub fn start_autostart(&self) -> Vec<(&'static str, ServerError)> {
20        let mut failures = Vec::new();
21        let mut guard = self.inner.lock().unwrap_or_else(|p| p.into_inner());
22        for service in guard.iter_mut().filter(|s| !s.on_demand()) {
23            if let Err(error) = service.start() {
24                failures.push((service.name(), error));
25            }
26        }
27        failures
28    }
29
30    /// Start one named subservice (on-demand request path).
31    pub fn start_named(&self, name: &str) -> Result<Status, ServerError> {
32        let mut guard = self.inner.lock().unwrap_or_else(|p| p.into_inner());
33        let service = guard
34            .iter_mut()
35            .find(|s| s.name() == name)
36            .ok_or_else(|| ServerError::Config(format!("unknown subservice {name}")))?;
37        service.start()?;
38        Ok(service.status())
39    }
40
41    pub fn stop_named(&self, name: &str) -> Result<Status, ServerError> {
42        let mut guard = self.inner.lock().unwrap_or_else(|p| p.into_inner());
43        let service = guard
44            .iter_mut()
45            .find(|s| s.name() == name)
46            .ok_or_else(|| ServerError::Config(format!("unknown subservice {name}")))?;
47        service.stop();
48        Ok(service.status())
49    }
50
51    pub fn statuses(&self) -> Vec<Status> {
52        let mut guard = self.inner.lock().unwrap_or_else(|p| p.into_inner());
53        guard.iter_mut().map(|s| s.status()).collect()
54    }
55
56    pub fn stop_all(&self) {
57        let mut guard = self.inner.lock().unwrap_or_else(|p| p.into_inner());
58        for service in guard.iter_mut() {
59            service.stop();
60        }
61    }
62}