Expand description
§rsActor
A Simple and Efficient In-Process Actor Model Implementation for Rust
rsActor
is a lightweight, Tokio-based actor framework in Rust focused on providing a simple
and efficient actor model for local, in-process systems. It emphasizes clean message-passing
semantics and straightforward actor lifecycle management while maintaining high performance for
Rust applications.
§Features
- Asynchronous Actors: Actors run in their own asynchronous tasks.
- Message Passing: Actors communicate by sending and receiving messages.
tell
: Send a message without waiting for a reply (fire-and-forget).tell_with_timeout
: Send a message without waiting for a reply, with a specified timeout.ask
: Send a message and await a reply.ask_with_timeout
: Send a message and await a reply, with a specified timeout.tell_blocking
: Blocking version oftell
for use intokio::task::spawn_blocking
tasks.ask_blocking
: Blocking version ofask
for use intokio::task::spawn_blocking
tasks.
- Straightforward Actor Lifecycle: Actors have
on_start
,on_run
, andon_stop
lifecycle hooks that provide a clean and intuitive actor lifecycle management system. The framework manages the execution flow while giving developers full control over actor behavior. - Graceful Shutdown & Kill: Actors can be stopped gracefully or killed immediately.
- Typed Messages: Messages are strongly typed, and replies are also typed.
- Macro for Message Handling: The
impl_message_handler!
macro simplifies handling multiple message types. - Type Safety Features: Two actor reference types provide different levels of type safety:
ActorRef<T>
: Compile-time type safety with zero runtime overhead (recommended)UntypedActorRef
: Runtime type handling for collections and dynamic scenarios
§Core Concepts
Actor
: Trait defining actor behavior and lifecycle hooks (on_start
required,on_run
optional).Message<M>
: Trait for handling a message typeM
and defining its reply type.ActorRef
: Handle for sending messages to an actor.spawn
: Function to create and start an actor, returning anActorRef
and aJoinHandle
.MessageHandler
: Trait for type-erased message handling. This is typically implemented automatically by theimpl_message_handler!
macro.ActorResult
: Enum representing the outcome of an actor’s lifecycle (e.g., completed, failed).
§Getting Started
Define an actor struct, implement Actor
and Message<M>
for each message type,
then use impl_message_handler!
to wire up message handling.
use rsactor::{Actor, ActorRef, Message, impl_message_handler, spawn};
use anyhow::Result;
// 1. Define your actor struct
#[derive(Debug)]
struct MyActor {
data: String,
tick_300ms: tokio::time::Interval,
tick_1s: tokio::time::Interval,
}
// 2. Implement the Actor trait
impl Actor for MyActor {
type Args = String;
type Error = anyhow::Error;
async fn on_start(args: Self::Args, _actor_ref: &ActorRef<Self>) -> std::result::Result<Self, Self::Error> {
println!("MyActor (data: '{}') started!", args);
Ok(MyActor {
data: args,
tick_300ms: tokio::time::interval(std::time::Duration::from_millis(300)),
tick_1s: tokio::time::interval(std::time::Duration::from_secs(1)),
})
}
async fn on_run(&mut self, _actor_ref: &ActorRef<Self>) -> Result<(), Self::Error> {
tokio::select! {
_ = self.tick_300ms.tick() => {
println!("Tick: 300ms");
}
_ = self.tick_1s.tick() => {
println!("Tick: 1s");
}
}
Ok(())
}
}
// 3. Define message types
struct GetData;
struct UpdateData(String);
// 4. Implement Message<M> for each message type
impl Message<GetData> for MyActor {
type Reply = String;
async fn handle(&mut self, _msg: GetData, _actor_ref: &ActorRef<Self>) -> Self::Reply {
self.data.clone()
}
}
impl Message<UpdateData> for MyActor {
type Reply = ();
async fn handle(&mut self, msg: UpdateData, _actor_ref: &ActorRef<Self>) -> Self::Reply {
self.data = msg.0;
println!("MyActor data updated!");
}
}
// 5. Use the macro to implement MessageHandler
impl_message_handler!(MyActor, [GetData, UpdateData]);
#[tokio::main]
async fn main() -> Result<()> {
let (actor_ref, join_handle) = spawn::<MyActor>("initial data".to_string());
// Send messages
let current_data: String = actor_ref.ask(GetData).await?;
println!("Received data: {}", current_data);
actor_ref.tell(UpdateData("new data".to_string())).await?;
let updated_data: String = actor_ref.ask(GetData).await?;
println!("Updated data: {}", updated_data);
// Stop the actor
actor_ref.stop().await?;
let actor_result = join_handle.await?;
println!("Actor stopped with result: {:?}", actor_result);
Ok(())
}
This crate-level documentation provides an overview of rsActor
.
For more details on specific components, please refer to their individual
documentation.
Macros§
- impl_
message_ handler - Implements the
MessageHandler
trait for both generic and non-generic actor types.
Structs§
- Actor
Ref - A type-safe reference to an actor of type
T
. - Identity
- Untyped
Actor Ref - A type-erased reference to an actor, allowing messages to be sent to it without type safety.
Enums§
- Actor
Result - Result type returned when an actor’s lifecycle completes.
- Error
- Represents errors that can occur in the rsactor framework.
- Failure
Phase - Represents the phase during which an actor failure occurred.
Constants§
- DEFAULT_
MAILBOX_ CAPACITY - The default mailbox capacity for actors.
Traits§
- Actor
- Defines the behavior of an actor.
- Message
- A trait for messages that an actor can handle, defining the reply type.
- Message
Handler - A trait for type-erased message handling within the actor system.
Functions§
- set_
default_ mailbox_ capacity - Sets the global default buffer size for actor mailboxes.
- spawn
- Spawns a new actor and returns an
ActorRef<T>
to it, along with aJoinHandle
. - spawn_
with_ mailbox_ capacity - Spawns a new actor with a specified mailbox capacity and returns an
ActorRef<T>
to it, along with aJoinHandle
.
Type Aliases§
- Result
- A Result type specialized for rsactor operations.