Skip to main content

hydra/
child_spec.rs

1use std::future::Future;
2use std::sync::Arc;
3
4use serde::Deserialize;
5use serde::Serialize;
6
7use crate::ExitReason;
8use crate::Pid;
9use crate::Restart;
10use crate::Shutdown;
11
12/// The type of child process.
13#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
14pub enum ChildType {
15    /// The child is a worker process.
16    Worker,
17    /// The child is a supervisor process.
18    Supervisor,
19}
20
21/// The child specification describes how the supervisor starts, shuts down, and restarts child processes.
22#[derive(Clone)]
23pub struct ChildSpec {
24    pub(crate) id: String,
25    #[allow(clippy::type_complexity)]
26    pub(crate) start: Option<
27        Arc<
28            dyn Fn() -> Box<dyn Future<Output = Result<Pid, ExitReason>> + Send + Sync>
29                + Send
30                + Sync,
31        >,
32    >,
33    pub(crate) restart: Restart,
34    pub(crate) shutdown: Option<Shutdown>,
35    pub(crate) child_type: ChildType,
36    pub(crate) significant: bool,
37}
38
39impl ChildSpec {
40    /// Constructs a new instance of [ChildSpec] with the given id.
41    pub fn new<T: Into<String>>(id: T) -> Self {
42        Self {
43            id: id.into(),
44            start: None,
45            restart: Restart::Permanent,
46            shutdown: None,
47            child_type: ChildType::Worker,
48            significant: false,
49        }
50    }
51
52    /// Sets a new id for this [ChildSpec].
53    pub fn id<T: Into<String>>(mut self, id: T) -> Self {
54        self.id = id.into();
55        self
56    }
57
58    /// The method invoked to start the child process.
59    ///
60    /// Must return a future that resolves to [Result<Pid, ExitReason>].
61    pub fn start<T, F>(mut self, start: T) -> Self
62    where
63        T: Fn() -> F + Send + Sync + 'static,
64        F: Future<Output = Result<Pid, ExitReason>> + Send + Sync + 'static,
65    {
66        self.start = Some(Arc::new(move || Box::new(start())));
67        self
68    }
69
70    /// Defines when a terminated child process should be restarted.
71    ///
72    /// Defaults to [Restart::Permanent].
73    pub const fn restart(mut self, restart: Restart) -> Self {
74        self.restart = restart;
75        self
76    }
77
78    /// Defines how a process should be terminated, specifically how long to wait before forcefully killing it.
79    ///
80    /// Defaults to 5s if the type is `worker` or infinity if the type is `supervisor`.
81    pub fn shutdown<T: Into<Shutdown>>(mut self, shutdown: T) -> Self {
82        self.shutdown = Some(shutdown.into());
83        self
84    }
85
86    /// Specifies the type of child process.
87    pub const fn child_type(mut self, child_type: ChildType) -> Self {
88        self.child_type = child_type;
89        self
90    }
91
92    /// A boolean indicating if the child process should be considered significant with regard to automatic shutdown.
93    ///
94    /// Only `transient` and `temporary` child processes can be marked as significant.
95    ///
96    /// Defaults to `false`.
97    pub const fn significant(mut self, significant: bool) -> Self {
98        if significant
99            && !matches!(self.restart, Restart::Temporary)
100            && !matches!(self.restart, Restart::Transient)
101        {
102            panic!("Only temporary/transient children can be marked significant!");
103        }
104
105        self.significant = significant;
106        self
107    }
108}