Skip to main content

compio_actor/supervisor/
mod.rs

1//! Actor lifecycle notifications.
2//!
3//! A supervisor is an ordinary actor that handles [`SupervisionEvent`] for a
4//! child type. Attach it while spawning the child:
5//!
6//! ```rust
7//! use std::{convert::Infallible, marker::PhantomData};
8//!
9//! use compio_actor::{Actor, Cluster, Handler, Mailbox, supervisor::SupervisionEvent};
10//!
11//! struct Child;
12//! struct Supervisor<C>(PhantomData<fn() -> C>);
13//!
14//! impl<C> Supervisor<C> {
15//!     fn new() -> Self {
16//!         Self(PhantomData)
17//!     }
18//! }
19//!
20//! # impl Actor for Child {
21//! #     type Arguments = ();
22//! #     type Error = Infallible;
23//! #     type State = ();
24//! #
25//! #     async fn pre_start(
26//! #         &self,
27//! #         _myself: &Mailbox<Self>,
28//! #         (): Self::Arguments,
29//! #     ) -> Result<Self::State, Self::Error> {
30//! #         Ok(())
31//! #     }
32//! # }
33//! #
34//! # impl<C: Actor> Actor for Supervisor<C> {
35//! #     type Arguments = ();
36//! #     type Error = Infallible;
37//! #     type State = ();
38//! #
39//! #     async fn pre_start(
40//! #         &self,
41//! #         _myself: &Mailbox<Self>,
42//! #         (): Self::Arguments,
43//! #     ) -> Result<Self::State, Self::Error> {
44//! #         Ok(())
45//! #     }
46//! # }
47//!
48//! impl<C: Actor> Handler<SupervisionEvent<C>> for Supervisor<C> {
49//!     async fn handle(
50//!         &self,
51//!         _myself: &Mailbox<Self>,
52//!         event: SupervisionEvent<C>,
53//!         _state: &mut Self::State,
54//!     ) -> Result<(), Self::Error> {
55//!         match event {
56//!             SupervisionEvent::ActorStarted(child) => {
57//!                 child.stop();
58//!             }
59//!             SupervisionEvent::ActorTerminated(_) => {}
60//!             SupervisionEvent::ActorFailed(_) => {}
61//!         }
62//!         Ok(())
63//!     }
64//! }
65//!
66//! # async fn example() -> std::io::Result<()> {
67//! let cluster = Cluster::new()?;
68//! let (supervisor, _supervisor_handle) =
69//!     cluster.spawn(Supervisor::<Child>::new, ()).await.unwrap();
70//! let (_child, _child_handle) = cluster
71//!     .spawn(|| Child, ())
72//!     .with_supervisor(&supervisor)
73//!     .await
74//!     .unwrap();
75//! # Ok(())
76//! # }
77//! ```
78
79use std::fmt;
80
81use crate::{Actor, Broker, Handler, Mailbox};
82
83/// A lifecycle event emitted by a supervised actor.
84pub enum SupervisionEvent<A: Actor> {
85    /// The actor completed its startup hooks.
86    ActorStarted(Mailbox<A>),
87    /// The actor stopped normally.
88    ActorTerminated(Mailbox<A>),
89    /// The actor exited after a lifecycle or handler error.
90    ActorFailed(Mailbox<A>),
91}
92
93impl<A: Actor> SupervisionEvent<A> {
94    /// Returns the actor that emitted this event.
95    pub fn actor(&self) -> &Mailbox<A> {
96        match self {
97            Self::ActorStarted(actor) | Self::ActorTerminated(actor) | Self::ActorFailed(actor) => {
98                actor
99            }
100        }
101    }
102}
103
104impl<A: Actor> fmt::Debug for SupervisionEvent<A> {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        match self {
107            Self::ActorStarted(actor) => f.debug_tuple("ActorStarted").field(actor).finish(),
108            Self::ActorTerminated(actor) => f.debug_tuple("ActorTerminated").field(actor).finish(),
109            Self::ActorFailed(actor) => f.debug_tuple("ActorFailed").field(actor).finish(),
110        }
111    }
112}
113
114pub(crate) struct Supervision<A: Actor> {
115    broker: Broker<SupervisionEvent<A>>,
116}
117
118impl<A: Actor> Supervision<A> {
119    pub(crate) fn new<S>(supervisor: &Mailbox<S>) -> Self
120    where
121        S: Handler<SupervisionEvent<A>>,
122    {
123        Self {
124            broker: supervisor.broker(),
125        }
126    }
127
128    pub(crate) fn started(&self, actor: &Mailbox<A>) {
129        self.broker
130            .send(SupervisionEvent::ActorStarted(actor.clone()))
131            .ok();
132    }
133
134    pub(crate) fn terminated(&self, actor: &Mailbox<A>) {
135        self.broker
136            .send(SupervisionEvent::ActorTerminated(actor.clone()))
137            .ok();
138    }
139
140    pub(crate) fn failed(&self, actor: &Mailbox<A>) {
141        self.broker
142            .send(SupervisionEvent::ActorFailed(actor.clone()))
143            .ok();
144    }
145}