bastion/callbacks.rs
1use std::fmt::{self, Debug, Formatter};
2use std::sync::Arc;
3
4#[derive(Debug, Clone)]
5#[allow(dead_code)]
6pub(crate) enum CallbackType {
7 AfterRestart,
8 AfterStop,
9 BeforeRestart,
10 BeforeStart,
11 AfterStart,
12}
13
14#[derive(Default, Clone)]
15/// A set of methods that will get called at different states of
16/// a [`Supervisor`] or [`Children`] life.
17///
18/// # Example
19///
20/// ```rust
21/// # use bastion::prelude::*;
22/// #
23/// # #[cfg(feature = "tokio-runtime")]
24/// # #[tokio::main]
25/// # async fn main() {
26/// # run();
27/// # }
28/// #
29/// # #[cfg(not(feature = "tokio-runtime"))]
30/// # fn main() {
31/// # run();
32/// # }
33/// #
34/// # fn run() {
35/// # Bastion::init();
36/// #
37/// Bastion::children(|children| {
38/// let callbacks = Callbacks::new()
39/// .with_before_start(|| println!("Children group started."))
40/// .with_after_stop(|| println!("Children group stopped."));
41///
42/// children
43/// .with_callbacks(callbacks)
44/// .with_exec(|ctx| {
45/// // -- Children group started.
46/// async move {
47/// // ...
48/// # Ok(())
49/// }
50/// // -- Children group stopped.
51/// })
52/// }).expect("Couldn't create the children group.");
53/// #
54/// # Bastion::start();
55/// # Bastion::stop();
56/// # Bastion::block_until_stopped();
57/// # }
58/// ```
59///
60/// [`Supervisor`]: crate::supervisor::Supervisor
61/// [`Children`]: crate::children::Children
62pub struct Callbacks {
63 before_start: Option<Arc<dyn Fn() + Send + Sync>>,
64 after_start: Option<Arc<dyn Fn() + Send + Sync>>,
65 before_restart: Option<Arc<dyn Fn() + Send + Sync>>,
66 after_restart: Option<Arc<dyn Fn() + Send + Sync>>,
67 after_stop: Option<Arc<dyn Fn() + Send + Sync>>,
68}
69
70impl Callbacks {
71 /// Creates a new instance of `Callbacks` for
72 /// [`Supervisor::with_callbacks`] or [`Children::with_callbacks`].
73 ///
74 /// # Example
75 ///
76 /// ```rust
77 /// # use bastion::prelude::*;
78 /// #
79 /// # #[cfg(feature = "tokio-runtime")]
80 /// # #[tokio::main]
81 /// # async fn main() {
82 /// # run();
83 /// # }
84 /// #
85 /// # #[cfg(not(feature = "tokio-runtime"))]
86 /// # fn main() {
87 /// # run();
88 /// # }
89 /// #
90 /// # fn run() {
91 /// # Bastion::init();
92 /// #
93 /// Bastion::children(|children| {
94 /// let callbacks = Callbacks::new()
95 /// .with_before_start(|| println!("Children group started."))
96 /// .with_after_stop(|| println!("Children group stopped."));
97 ///
98 /// children
99 /// .with_callbacks(callbacks)
100 /// .with_exec(|ctx| {
101 /// // -- Children group started.
102 /// async move {
103 /// // ...
104 /// # Ok(())
105 /// }
106 /// // -- Children group stopped.
107 /// })
108 /// }).expect("Couldn't create the children group.");
109 /// #
110 /// # Bastion::start();
111 /// # Bastion::stop();
112 /// # Bastion::block_until_stopped();
113 /// # }
114 /// ```
115 ///
116 /// [`Supervisor::with_callbacks`]: crate::supervisor::Supervisor::with_callbacks
117 /// [`Children::with_callbacks`]: crate::children::Children::with_callbacks
118 pub fn new() -> Self {
119 Callbacks::default()
120 }
121
122 /// Sets the method that will get called before the [`Supervisor`]
123 /// or [`Children`] is launched if:
124 /// - it was never called before
125 /// - or the supervisor of the supervised element using this callback
126 /// (or the system) decided to restart it and it was already
127 /// stopped or killed
128 /// - or the supervisor of the supervised element using this callback
129 /// (or the system) decided to restart it and it wasn't already
130 /// stopped or killed but did not have a callback defined using
131 /// [`with_after_restart`]
132 ///
133 /// # Example
134 ///
135 /// ```rust
136 /// # use bastion::prelude::*;
137 /// #
138 /// # #[cfg(feature = "tokio-runtime")]
139 /// # #[tokio::main]
140 /// # async fn main() {
141 /// # run();
142 /// # }
143 /// #
144 /// # #[cfg(not(feature = "tokio-runtime"))]
145 /// # fn main() {
146 /// # run();
147 /// # }
148 /// #
149 /// # fn run() {
150 /// # Bastion::init();
151 /// #
152 /// # Bastion::supervisor(|supervisor| {
153 /// supervisor.children(|children| {
154 /// let callbacks = Callbacks::new()
155 /// .with_before_start(|| println!("Children group started."))
156 /// .with_before_restart(|| println!("Children group restarting."))
157 /// .with_after_restart(|| println!("Children group restarted."))
158 /// .with_after_stop(|| println!("Children group stopped."));
159 ///
160 /// children
161 /// .with_exec(|ctx| {
162 /// // -- Children group started.
163 /// async move {
164 /// // ...
165 ///
166 /// // This will stop the children group...
167 /// Ok(())
168 /// // Note that because the children group stopped by itself,
169 /// // if its supervisor restarts it, its `before_start` callback
170 /// // will get called and not `after_restart`.
171 /// }
172 /// // -- Children group stopped.
173 /// })
174 /// .with_callbacks(callbacks)
175 /// })
176 /// # }).unwrap();
177 /// #
178 /// # Bastion::start();
179 /// # Bastion::stop();
180 /// # Bastion::block_until_stopped();
181 /// # }
182 /// ```
183 ///
184 /// [`Supervisor`]: crate::supervisor::Supervisor
185 /// [`Children`]: crate::children::Children
186 /// [`with_after_restart`]: Self::with_after_restart
187 pub fn with_before_start<C>(mut self, before_start: C) -> Self
188 where
189 C: Fn() + Send + Sync + 'static,
190 {
191 let before_start = Arc::new(before_start);
192 self.before_start = Some(before_start);
193 self
194 }
195
196 /// Sets the method that will get called right after the [`Supervisor`]
197 /// or [`Children`] is launched.
198 /// This method will be called after the child has subscribed to its distributors and dispatchers.
199 ///
200 /// Once the callback has run, the child has caught up it's message backlog,
201 /// and is waiting for new messages to process.
202 ///
203 /// # Example
204 ///
205 /// ```rust
206 /// # use bastion::prelude::*;
207 /// #
208 /// # #[cfg(feature = "tokio-runtime")]
209 /// # #[tokio::main]
210 /// # async fn main() {
211 /// # run();
212 /// # }
213 /// #
214 /// # #[cfg(not(feature = "tokio-runtime"))]
215 /// # fn main() {
216 /// # run();
217 /// # }
218 /// #
219 /// # fn run() {
220 /// # Bastion::init();
221 /// #
222 /// # Bastion::supervisor(|supervisor| {
223 /// supervisor.children(|children| {
224 /// let callbacks = Callbacks::new()
225 /// .with_after_start(|| println!("Children group ready to process messages."));
226 ///
227 /// children
228 /// .with_exec(|ctx| {
229 /// // -- Children group started.
230 /// // with_after_start called
231 /// async move {
232 /// // ...
233 ///
234 /// // This will stop the children group...
235 /// Ok(())
236 /// // Note that because the children group stopped by itself,
237 /// // if its supervisor restarts it, its `before_start` callback
238 /// // will get called and not `after_restart`.
239 /// }
240 /// // -- Children group stopped.
241 /// })
242 /// .with_callbacks(callbacks)
243 /// })
244 /// # }).unwrap();
245 /// #
246 /// # Bastion::start();
247 /// # Bastion::stop();
248 /// # Bastion::block_until_stopped();
249 /// # }
250 /// ```
251 ///
252 /// [`Supervisor`]: crate::supervisor::Supervisor
253 /// [`Children`]: crate::children::Children
254 /// [`with_after_restart`]: Self::with_after_restart
255 pub fn with_after_start<C>(mut self, after_start: C) -> Self
256 where
257 C: Fn() + Send + Sync + 'static,
258 {
259 let after_start = Arc::new(after_start);
260 self.after_start = Some(after_start);
261 self
262 }
263
264 /// Sets the method that will get called before the [`Supervisor`]
265 /// or [`Children`] is reset if:
266 /// - the supervisor of the supervised element using this callback
267 /// (or the system) decided to restart it and it wasn't already
268 /// stopped or killed
269 ///
270 /// Note that if this callback isn't defined but one was defined using
271 /// [`with_after_stop`], it will get called instead.
272 ///
273 /// # Example
274 ///
275 /// ```rust
276 /// # use bastion::prelude::*;
277 /// #
278 /// # #[cfg(feature = "tokio-runtime")]
279 /// # #[tokio::main]
280 /// # async fn main() {
281 /// # run();
282 /// # }
283 /// #
284 /// # #[cfg(not(feature = "tokio-runtime"))]
285 /// # fn main() {
286 /// # run();
287 /// # }
288 /// #
289 /// # fn run() {
290 /// # Bastion::init();
291 /// #
292 /// # Bastion::supervisor(|supervisor| {
293 /// supervisor.children(|children| {
294 /// let callbacks = Callbacks::new()
295 /// .with_before_start(|| println!("Children group started."))
296 /// .with_before_restart(|| println!("Children group restarting."))
297 /// .with_after_restart(|| println!("Children group restarted."))
298 /// .with_after_stop(|| println!("Children group stopped."));
299 ///
300 /// children
301 /// .with_exec(|ctx| {
302 /// // Once -- Children group started.
303 /// // and then -- Children group restarted.
304 /// async move {
305 /// // ...
306 ///
307 /// // This will make the children group fault and get
308 /// // restarted by its supervisor...
309 /// Err(())
310 /// }
311 /// // -- Children group restarting.
312 /// // Note that if a `before_restart` wasn't specified for
313 /// // this children group, `after_stop` would get called
314 /// // instead.
315 /// })
316 /// .with_callbacks(callbacks)
317 /// })
318 /// # }).unwrap();
319 /// #
320 /// # Bastion::start();
321 /// # Bastion::stop();
322 /// # Bastion::block_until_stopped();
323 /// # }
324 /// ```
325 ///
326 /// [`Supervisor`]: crate::supervisor::Supervisor
327 /// [`Children`]: crate::children::Children
328 /// [`with_after_stop`]: Self::with_after_stop
329 pub fn with_before_restart<C>(mut self, before_restart: C) -> Self
330 where
331 C: Fn() + Send + Sync + 'static,
332 {
333 let before_restart = Arc::new(before_restart);
334 self.before_restart = Some(before_restart);
335 self
336 }
337
338 /// Sets the method that will get called before the [`Supervisor`]
339 /// or [`Children`] is launched if:
340 /// - the supervisor of the supervised element using this callback
341 /// (or the system) decided to restart it and it wasn't already
342 /// stopped or killed
343 ///
344 /// Note that if this callback isn't defined but one was defined using
345 /// [`with_before_start`], it will get called instead.
346 ///
347 /// # Example
348 ///
349 /// ```rust
350 /// # use bastion::prelude::*;
351 /// #
352 /// # #[cfg(feature = "tokio-runtime")]
353 /// # #[tokio::main]
354 /// # async fn main() {
355 /// # run();
356 /// # }
357 /// #
358 /// # #[cfg(not(feature = "tokio-runtime"))]
359 /// # fn main() {
360 /// # run();
361 /// # }
362 /// #
363 /// # fn run() {
364 /// # Bastion::init();
365 /// #
366 /// # Bastion::supervisor(|supervisor| {
367 /// supervisor.children(|children| {
368 /// let callbacks = Callbacks::new()
369 /// .with_before_start(|| println!("Children group started."))
370 /// .with_before_restart(|| println!("Children group restarting."))
371 /// .with_after_restart(|| println!("Children group restarted."))
372 /// .with_after_stop(|| println!("Children group stopped."));
373 ///
374 /// children
375 /// .with_exec(|ctx| {
376 /// // Once -- Children group started.
377 /// // and then -- Children group restarted.
378 /// // Note that if a `after_restart` callback wasn't specified
379 /// // for this children group, `before_restart` would get called
380 /// // instead.
381 /// async move {
382 /// // ...
383 ///
384 /// // This will make the children group fault and get
385 /// // restarted by its supervisor...
386 /// Err(())
387 /// }
388 /// // -- Children group restarting.
389 /// })
390 /// .with_callbacks(callbacks)
391 /// })
392 /// # }).unwrap();
393 /// #
394 /// # Bastion::start();
395 /// # Bastion::stop();
396 /// # Bastion::block_until_stopped();
397 /// # }
398 /// ```
399 ///
400 /// [`Supervisor`]: crate::supervisor::Supervisor
401 /// [`Children`]: crate::children::Children
402 /// [`with_before_start`]: Self::method.with_before_start
403 pub fn with_after_restart<C>(mut self, after_restart: C) -> Self
404 where
405 C: Fn() + Send + Sync + 'static,
406 {
407 let after_restart = Arc::new(after_restart);
408 self.after_restart = Some(after_restart);
409 self
410 }
411
412 /// Sets the method that will get called after the [`Supervisor`]
413 /// or [`Children`] is stopped or killed if:
414 /// - the supervisor of the supervised element using this callback
415 /// (or the system) decided to stop (not restart nor kill) it and
416 /// it wasn't already stopped or killed
417 /// - or the supervisor or children group using this callback
418 /// stopped or killed itself or was stopped or killed by a
419 /// reference to it
420 /// - or the supervisor of the supervised element using this callback
421 /// (or the system) decided to restart it and it wasn't already
422 /// stopped or killed but did not have a callback defined using
423 /// [`with_before_restart`]
424 ///
425 /// # Example
426 ///
427 /// ```rust
428 /// # use bastion::prelude::*;
429 /// #
430 /// # #[cfg(feature = "tokio-runtime")]
431 /// # #[tokio::main]
432 /// # async fn main() {
433 /// # run();
434 /// # }
435 /// #
436 /// # #[cfg(not(feature = "tokio-runtime"))]
437 /// # fn main() {
438 /// # run();
439 /// # }
440 /// #
441 /// # fn run() {
442 /// # Bastion::init();
443 /// #
444 /// # Bastion::supervisor(|supervisor| {
445 /// supervisor.children(|children| {
446 /// let callbacks = Callbacks::new()
447 /// .with_before_start(|| println!("Children group started."))
448 /// .with_before_restart(|| println!("Children group restarting."))
449 /// .with_after_restart(|| println!("Children group restarted."))
450 /// .with_after_stop(|| println!("Children group stopped."));
451 ///
452 /// children
453 /// .with_exec(|ctx| {
454 /// // -- Children group started.
455 /// async move {
456 /// // ...
457 ///
458 /// // This will stop the children group...
459 /// Ok(())
460 /// }
461 /// // -- Children group stopped.
462 /// // Note that because the children group stopped by itself,
463 /// // it its supervisor restarts it, its `before_restart` callback
464 /// // will not get called.
465 /// })
466 /// .with_callbacks(callbacks)
467 /// })
468 /// # }).unwrap();
469 /// #
470 /// # Bastion::start();
471 /// # Bastion::stop();
472 /// # Bastion::block_until_stopped();
473 /// # }
474 /// ```
475 ///
476 /// [`Supervisor`]: crate::supervisor::Supervisor
477 /// [`Children`]: crate::children::Children
478 /// [`with_before_restart`]: Self::with_before_restart
479 pub fn with_after_stop<C>(mut self, after_stop: C) -> Self
480 where
481 C: Fn() + Send + Sync + 'static,
482 {
483 let after_stop = Arc::new(after_stop);
484 self.after_stop = Some(after_stop);
485 self
486 }
487
488 /// Returns whether a callback was defined using [`with_before_start`].
489 ///
490 /// # Example
491 ///
492 /// ```rust
493 /// # use bastion::prelude::*;
494 /// #
495 /// let callbacks = Callbacks::new()
496 /// .with_before_start(|| println!("Children group started."));
497 ///
498 /// assert!(callbacks.has_before_start());
499 /// ```
500 ///
501 /// [`with_before_start`]: Self::with_before_start
502 pub fn has_before_start(&self) -> bool {
503 self.before_start.is_some()
504 }
505
506 /// Returns whether a callback was defined using [`with_before_restart`].
507 ///
508 /// # Example
509 ///
510 /// ```rust
511 /// # use bastion::prelude::*;
512 /// #
513 /// let callbacks = Callbacks::new()
514 /// .with_before_restart(|| println!("Children group restarting."));
515 ///
516 /// assert!(callbacks.has_before_restart());
517 /// ```
518 ///
519 /// [`with_before_restart`]: Self::with_before_restart
520 pub fn has_before_restart(&self) -> bool {
521 self.before_restart.is_some()
522 }
523
524 /// Returns whether a callback was defined using [`with_after_restart`].
525 ///
526 /// # Example
527 ///
528 /// ```rust
529 /// # use bastion::prelude::*;
530 /// #
531 /// let callbacks = Callbacks::new()
532 /// .with_after_restart(|| println!("Children group restarted."));
533 ///
534 /// assert!(callbacks.has_after_restart());
535 /// ```
536 ///
537 /// [`with_after_restart`]: Self::with_after_restart
538 pub fn has_after_restart(&self) -> bool {
539 self.after_restart.is_some()
540 }
541
542 /// Returns whether a callback was defined using [`with_after_stop`].
543 ///
544 /// # Example
545 ///
546 /// ```rust
547 /// # use bastion::prelude::*;
548 /// #
549 /// let callbacks = Callbacks::new()
550 /// .with_after_stop(|| println!("Children group stopped."));
551 ///
552 /// assert!(callbacks.has_after_stop());
553 /// ```
554 ///
555 /// [`with_after_stop`]: Self::with_after_stop
556 pub fn has_after_stop(&self) -> bool {
557 self.after_stop.is_some()
558 }
559
560 pub(crate) fn before_start(&self) {
561 if let Some(before_start) = &self.before_start {
562 before_start()
563 }
564 }
565
566 pub(crate) fn after_start(&self) {
567 if let Some(after_start) = &self.after_start {
568 after_start()
569 }
570 }
571
572 pub(crate) fn before_restart(&self) {
573 if let Some(before_restart) = &self.before_restart {
574 before_restart()
575 } else {
576 self.after_stop()
577 }
578 }
579
580 pub(crate) fn after_restart(&self) {
581 if let Some(after_restart) = &self.after_restart {
582 after_restart()
583 } else {
584 self.before_start()
585 }
586 }
587
588 pub(crate) fn after_stop(&self) {
589 if let Some(after_stop) = &self.after_stop {
590 after_stop()
591 }
592 }
593}
594
595impl Debug for Callbacks {
596 fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
597 fmt.debug_struct("Callbacks")
598 .field("before_start", &self.before_start.is_some())
599 .field("before_restart", &self.before_start.is_some())
600 .field("after_restart", &self.before_start.is_some())
601 .field("after_stop", &self.before_start.is_some())
602 .finish()
603 }
604}