supervisor/
supervisor.rs

1use std::time::Duration;
2
3use serde::Deserialize;
4use serde::Serialize;
5
6use hydra::Application;
7use hydra::CallError;
8use hydra::ChildSpec;
9use hydra::Dest;
10use hydra::ExitReason;
11use hydra::From;
12use hydra::GenServer;
13use hydra::GenServerOptions;
14use hydra::Pid;
15use hydra::Process;
16use hydra::SupervisionStrategy;
17use hydra::Supervisor;
18use hydra::SupervisorOptions;
19
20#[derive(Debug, Serialize, Deserialize)]
21enum MyMessage {
22    Hello(String),
23    HelloResponse(String),
24    Crash,
25}
26
27struct MyApplication;
28
29impl Application for MyApplication {
30    async fn start(&self) -> Result<Pid, ExitReason> {
31        // Spawn two instances of `MyServer` with their own unique ids.
32        let children = [
33            MyServer::new().child_spec().id("server1"),
34            MyServer::new().child_spec().id("server2"),
35        ];
36
37        // Restart only the terminated child.
38        Supervisor::with_children(children)
39            .strategy(SupervisionStrategy::OneForOne)
40            .start_link(SupervisorOptions::new())
41            .await
42    }
43}
44
45#[derive(Clone)]
46struct MyServer;
47
48impl MyServer {
49    /// Constructs a new [MyServer].
50    pub fn new() -> Self {
51        Self
52    }
53
54    /// A wrapper around the GenServer call "Hello".
55    pub async fn hello<T: Into<Dest>>(server: T, string: &str) -> Result<String, CallError> {
56        use MyMessage::*;
57
58        match MyServer::call(server, Hello(string.to_owned()), None).await? {
59            HelloResponse(response) => Ok(response),
60            _ => unreachable!(),
61        }
62    }
63
64    /// Builds the child specification for [MyServer].
65    pub fn child_spec(self) -> ChildSpec {
66        ChildSpec::new("MyServer")
67            .start(move || MyServer::start_link(MyServer, GenServerOptions::new()))
68    }
69}
70
71impl GenServer for MyServer {
72    type Message = MyMessage;
73
74    async fn init(&mut self) -> Result<(), ExitReason> {
75        let server = Process::current();
76
77        Process::spawn(async move {
78            // Ask for a formatted string.
79            let hello_world = MyServer::hello(server, "hello")
80                .await
81                .expect("Failed to call server!");
82
83            tracing::info!("Got: {:?}", hello_world);
84
85            // Wait before crashing.
86            Process::sleep(Duration::from_secs(1)).await;
87
88            // Crash the process so the supervisor restarts it.
89            MyServer::cast(server, MyMessage::Crash);
90        });
91
92        Ok(())
93    }
94
95    async fn handle_call(
96        &mut self,
97        message: Self::Message,
98        _from: From,
99    ) -> Result<Option<Self::Message>, ExitReason> {
100        use MyMessage::*;
101
102        match message {
103            Hello(string) => Ok(Some(HelloResponse(format!("{} world!", string)))),
104            _ => unreachable!(),
105        }
106    }
107
108    async fn handle_cast(&mut self, message: Self::Message) -> Result<(), ExitReason> {
109        use MyMessage::*;
110
111        match message {
112            Crash => {
113                panic!("Whoops! We crashed!");
114            }
115            _ => unreachable!(),
116        }
117    }
118}
119
120fn main() {
121    // This method will only return once the supervisor linked in `start` has terminated.
122    Application::run(MyApplication)
123}