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}