kameo/actor.rs
1//! Core functionality for defining and managing actors in Kameo.
2//!
3//! Actors are independent units of computation that run asynchronously, sending and receiving messages.
4//! Each actor operates within its own task, and its lifecycle is managed by hooks such as `on_start`, `on_panic`, and `on_stop`.
5//!
6//! The actor trait is designed to support fault tolerance, recovery from panics, and clean termination.
7//! Lifecycle hooks allow customization of actor behavior when starting, encountering errors, or shutting down.
8//!
9//! This module contains the primary `Actor` trait, which all actors must implement,
10//! as well as types for managing message queues (mailboxes) and actor references ([`ActorRef`]).
11//!
12//! # Features
13//! - **Asynchronous Message Handling**: Each actor processes messages asynchronously within its own task.
14//! - **Lifecycle Hooks**: Customizable hooks ([`on_start`], [`on_stop`], [`on_panic`]) for managing the actor's lifecycle.
15//! - **Backpressure**: Mailboxes can be bounded or unbounded, controlling the flow of messages.
16//! - **Supervision**: Actors can be linked, enabling robust supervision and error recovery systems.
17//!
18//! This module allows building resilient, fault-tolerant, distributed systems with flexible control over the actor lifecycle.
19//!
20//! [`on_start`]: Actor::on_start
21//! [`on_stop`]: Actor::on_stop
22//! [`on_panic`]: Actor::on_panic
23
24mod actor_ref;
25mod id;
26mod kind;
27pub mod pool;
28pub mod pubsub;
29mod spawn;
30
31use std::any;
32
33use futures::Future;
34
35use crate::{
36 error::{ActorStopReason, BoxError, PanicError},
37 mailbox::Mailbox,
38};
39
40pub use actor_ref::*;
41pub use id::*;
42pub use spawn::*;
43
44/// Core behavior of an actor, including its lifecycle events and how it processes messages.
45///
46/// Every actor must implement this trait, which provides hooks
47/// for the actor's initialization ([`on_start`]), handling errors ([`on_panic`]), and cleanup ([`on_stop`]).
48///
49/// The actor runs within its own task and processes messages asynchronously from a mailbox.
50/// Each actor can be linked to others, allowing for robust supervision and failure recovery mechanisms.
51///
52/// Methods in this trait that return [`BoxError`] will cause the actor to stop with the reason
53/// [`ActorStopReason::Panicked`] if an error occurs. This enables graceful handling of actor panics
54/// or errors.
55///
56/// # Example with Derive
57///
58/// ```
59/// use kameo::Actor;
60///
61/// #[derive(Actor)]
62/// struct MyActor;
63/// ```
64///
65/// # Example Override Behaviour
66///
67/// ```
68/// use kameo::actor::{Actor, ActorRef, WeakActorRef};
69/// use kameo::error::{ActorStopReason, BoxError};
70/// use kameo::mailbox::unbounded::UnboundedMailbox;
71///
72/// struct MyActor;
73///
74/// impl Actor for MyActor {
75/// type Mailbox = UnboundedMailbox<Self>;
76///
77/// async fn on_start(&mut self, actor_ref: ActorRef<Self>) -> Result<(), BoxError> {
78/// println!("actor started");
79/// Ok(())
80/// }
81///
82/// async fn on_stop(
83/// &mut self,
84/// actor_ref: WeakActorRef<Self>,
85/// reason: ActorStopReason,
86/// ) -> Result<(), BoxError> {
87/// println!("actor stopped");
88/// Ok(())
89/// }
90/// }
91/// ```
92///
93/// # Lifecycle Hooks
94/// - `on_start`: Called when the actor starts. This is where initialization happens.
95/// - `on_panic`: Called when the actor encounters a panic or an error while processing a "tell" message.
96/// - `on_stop`: Called before the actor is stopped. This allows for cleanup tasks.
97/// - `on_link_died`: Hook that is invoked when a linked actor dies.
98///
99/// # Mailboxes
100/// Actors use a mailbox to queue incoming messages. You can choose between:
101/// - **Bounded Mailbox**: Limits the number of messages that can be queued, providing backpressure.
102/// - **Unbounded Mailbox**: Allows an infinite number of messages, but can lead to high memory usage.
103///
104/// Mailboxes enable efficient asynchronous message passing with support for both backpressure and
105/// unbounded queueing depending on system requirements.
106///
107/// [`on_start`]: Actor::on_start
108/// [`on_stop`]: Actor::on_stop
109/// [`on_panic`]: Actor::on_panic
110pub trait Actor: Sized + Send + 'static {
111 /// The mailbox type used for the actor.
112 ///
113 /// This can either be a `BoundedMailbox<Self>` or an `UnboundedMailbox<Self>`, depending on
114 /// whether you want to enforce backpressure or allow infinite message queueing.
115 ///
116 /// - **Bounded Mailbox**: Prevents unlimited message growth, enforcing backpressure.
117 /// - **Unbounded Mailbox**: Allows an infinite number of messages, but can consume large amounts of memory.
118 type Mailbox: Mailbox<Self>;
119
120 /// The name of the actor, which can be useful for logging or debugging.
121 ///
122 /// # Default Implementation
123 /// By default, this returns the type name of the actor.
124 fn name() -> &'static str {
125 any::type_name::<Self>()
126 }
127
128 /// Creates a new mailbox for the actor. This sets up the message queue and receiver for the actor.
129 ///
130 /// # Returns
131 /// A tuple containing:
132 /// - The created mailbox for sending messages.
133 /// - The receiver for processing messages.
134 fn new_mailbox() -> (Self::Mailbox, <Self::Mailbox as Mailbox<Self>>::Receiver) {
135 Self::Mailbox::default_mailbox()
136 }
137
138 /// Called when the actor starts, before it processes any messages.
139 ///
140 /// Messages sent internally by the actor during `on_start` are prioritized and processed
141 /// before any externally sent messages, even if external messages are received first.
142 ///
143 /// This ensures that the actor can properly initialize before handling external messages.
144 #[allow(unused_variables)]
145 fn on_start(
146 &mut self,
147 actor_ref: ActorRef<Self>,
148 ) -> impl Future<Output = Result<(), BoxError>> + Send {
149 async { Ok(()) }
150 }
151
152 /// Called when the actor encounters a panic or an error during "tell" message handling.
153 ///
154 /// This method gives the actor an opportunity to clean up or reset its state and determine
155 /// whether it should be stopped or continue processing messages.
156 ///
157 /// # Parameters
158 /// - `err`: The panic or error that occurred.
159 ///
160 /// # Returns
161 /// - `Some(ActorStopReason)`: Stops the actor.
162 /// - `None`: Allows the actor to continue processing messages.
163 #[allow(unused_variables)]
164 fn on_panic(
165 &mut self,
166 actor_ref: WeakActorRef<Self>,
167 err: PanicError,
168 ) -> impl Future<Output = Result<Option<ActorStopReason>, BoxError>> + Send {
169 async move { Ok(Some(ActorStopReason::Panicked(err))) }
170 }
171
172 /// Called when a linked actor dies.
173 ///
174 /// By default, the actor will stop if the reason for the linked actor's death is anything other
175 /// than `Normal`. You can customize this behavior in the implementation.
176 ///
177 /// # Returns
178 /// Whether the actor should stop or continue processing messages.
179 #[allow(unused_variables)]
180 fn on_link_died(
181 &mut self,
182 actor_ref: WeakActorRef<Self>,
183 id: ActorID,
184 reason: ActorStopReason,
185 ) -> impl Future<Output = Result<Option<ActorStopReason>, BoxError>> + Send {
186 async move {
187 match &reason {
188 ActorStopReason::Normal => Ok(None),
189 ActorStopReason::Killed
190 | ActorStopReason::Panicked(_)
191 | ActorStopReason::LinkDied { .. } => Ok(Some(ActorStopReason::LinkDied {
192 id,
193 reason: Box::new(reason),
194 })),
195 #[cfg(feature = "remote")]
196 ActorStopReason::PeerDisconnected => Ok(Some(ActorStopReason::PeerDisconnected)),
197 }
198 }
199 }
200
201 /// Called before the actor stops.
202 ///
203 /// This allows the actor to perform any necessary cleanup or release resources before being fully stopped.
204 ///
205 /// # Parameters
206 /// - `reason`: The reason why the actor is being stopped.
207 #[allow(unused_variables)]
208 fn on_stop(
209 &mut self,
210 actor_ref: WeakActorRef<Self>,
211 reason: ActorStopReason,
212 ) -> impl Future<Output = Result<(), BoxError>> + Send {
213 async { Ok(()) }
214 }
215}