agner_sup/common/
stop_child.rs

1use std::time::Duration;
2
3use agner_actors::{ActorID, Exit, System};
4use agner_utils::future_timeout_ext::FutureTimeoutExt;
5
6const DEFAULT_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
7const DEFAULT_KILL_TIMEOUT: Duration = Duration::from_secs(5);
8
9#[derive(Debug, thiserror::Error)]
10#[error("Exit failed")]
11pub struct StopChildError;
12
13#[derive(Debug, Clone)]
14pub struct ShutdownSequence(Vec<(Exit, Duration)>);
15
16/// Stop the child in accordance with the supervision design principles.
17pub async fn stop_child(
18    system: System,
19    actor_id: ActorID,
20    shutdown_sequence: ShutdownSequence,
21) -> Result<Exit, StopChildError> {
22    for (exit, timeout) in shutdown_sequence.0.into_iter() {
23        system.exit(actor_id, exit).await;
24        if let Ok(actual_exit) = system.wait(actor_id).timeout(timeout).await {
25            return Ok(actual_exit)
26        }
27    }
28    Err(StopChildError)
29}
30
31impl Default for ShutdownSequence {
32    fn default() -> Self {
33        [(Exit::shutdown(), DEFAULT_SHUTDOWN_TIMEOUT), (Exit::kill(), DEFAULT_KILL_TIMEOUT)].into()
34    }
35}
36
37impl ShutdownSequence {
38    pub fn empty() -> Self {
39        Self(vec![])
40    }
41    pub fn add(mut self, exit: Exit, timeout: Duration) -> Self {
42        self.0.push((exit, timeout));
43        self
44    }
45}
46
47impl<I> From<I> for ShutdownSequence
48where
49    I: IntoIterator<Item = (Exit, Duration)>,
50{
51    fn from(seq: I) -> Self {
52        Self(seq.into_iter().collect())
53    }
54}