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}