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.
Note: This project is actively evolving. While core APIs are stable, some features may be refined in future releases.
Core Features
- Minimalist Actor System: Focuses on core actor model primitives.
- Actor Derive Macro:
#[derive(Actor)]for simple actors that don't need complex initialization. - Message Passing:
ask/ask_with_timeout: Send a message and asynchronously await a reply.tell/tell_with_timeout: Send a message without waiting for a reply.ask_blocking/tell_blocking: Blocking versions fortokio::task::spawn_blockingcontexts.
- Straightforward Actor Lifecycle: Provides
on_start,on_run, andon_stophooks for managing actor behavior:on_start:async fn on_start(args: Self::Args, actor_ref: &ActorRef<Self>) -> Result<Self, Self::Error>- Initializes the actor's state. This method is required.on_run:async fn on_run(&mut self, actor_ref: &ActorWeak<Self>) -> Result<(), Self::Error>- Contains the actor's main execution logic, which runs concurrently with message handling. This method is optional and has a default implementation.on_stop:async fn on_stop(&mut self, actor_ref: &ActorWeak<Self>, killed: bool) -> Result<(), Self::Error>- Performs cleanup before the actor terminates. Thekilledflag indicates whether the termination was graceful (false) or immediate (true). This method is optional and has a default implementation.
- Graceful & Immediate Termination: Actors can be stopped gracefully or killed.
ActorResult: Enum representing the outcome of an actor's lifecycle (e.g., completed, failed).- Macro-Assisted Message Handling:
#[message_handlers]attribute macro with#[handler]method attributes for automatic message handling
- Tokio-Native: Built for the
tokioasynchronous runtime. - Strong Type Safety: Provides compile-time (
ActorRef<T>) type safety, ensuring message handling consistency and preventing type-related runtime errors. - Handler Traits:
TellHandler<M>andAskHandler<M, R>traits enable unified management of different actor types handling the same message in a single collection. - Only
SendTrait Required: Actor structs only need to implement theSendtrait (notSync), enabling the use of interior mutability types likestd::cell::Cellfor internal state management without synchronization overhead. TheActortrait andMessageHandlertrait (via#[message_handlers]macro) are also required, but they don't add any additional constraints on the actor's fields. - Optional Tracing Support: Built-in support for detailed observability using the
tracingcrate. When enabled via thetracingfeature flag, provides comprehensive logging of actor lifecycle events, message handling, and performance metrics.
Getting Started
1. Add Dependency
[]
= "0.11" # Check crates.io for the latest version
# Optional: Enable tracing support for detailed observability
# rsactor = { version = "0.11", features = ["tracing"] }
For using the derive macros, you'll also need the message_handlers attribute macro which is included by default.
2. Message Handling with #[message_handlers]
rsActor uses the #[message_handlers] attribute macro combined with #[handler] method attributes for message handling. This is required for all actors and offers several advantages:
- Selective Processing: Only methods marked with
#[handler]are treated as message handlers. - Clean Separation: Regular methods can coexist with message handlers within the same
implblock. - Automatic Generation: The macro automatically generates the necessary
Messagetrait implementations and handler registrations. - Type Safety: Message handler signatures are verified at compile time.
- Reduced Boilerplate: Eliminates the need to manually implement
Messagetraits.
3. Choose Your Actor Creation Approach
Option A: Simple Actor with #[derive(Actor)]
For simple actors that don't need complex initialization logic, use the #[derive(Actor)] macro:
use ;
// 1. Define message types
;
;
// 2. Define your actor struct and derive Actor
// 3. Use the #[message_handlers] macro with #[handler] attributes to automatically generate Message trait implementations
// 4. Usage
async
Option B: Custom Actor Implementation with Manual Initialization
For actors that need custom initialization logic, implement the Actor trait manually:
use ;
use Result;
use info;
// Define actor struct
// Added Debug for printing the actor in ActorResult
// Implement Actor trait
// Define message types
;
// Use message_handlers macro for message handling
async
Examples
rsActor comes with several examples that demonstrate various features and use cases:
- basic - Simple counter actor demonstrating core actor model concepts with
#[message_handlers]macro - derive_macro_demo - Simple example using
#[message_handlers]with#[handler]attributes - message_macro_demo - Demonstrates various message types with the new macro system
- unified_macro_demo - Combined usage of derive and message handler macros
- advanced_derive_demo - Advanced usage patterns with derive macros
- actor_with_timeout - Using timeouts for actor communication
- actor_async_worker - Inter-actor communication with async tasks
- actor_task - Background task communication with actors
- actor_blocking_task - Using blocking APIs with actors
- dining_philosophers - Classic concurrency problem implementation
- weak_reference_demo - Working with weak actor references and lifecycle management
- handler_demo - Using handler traits for unified actor management
Run any example with:
All examples support tracing when enabled with the tracing feature:
RUST_LOG=debug
Optional Features
Tracing Support
rsActor provides optional tracing support for comprehensive observability into actor behavior. When enabled, the framework emits structured trace events for:
- Actor lifecycle events (start, stop, termination scenarios)
- Message sending and handling with timing information
- Reply processing and error handling
- Performance metrics (message processing duration)
To enable tracing support, add the tracing feature to your dependencies:
[]
= { = "0.11", = ["tracing"] }
= "0.1"
= "0.3"
All examples include tracing support with feature detection. Here's the pattern used:
async
Run any example with tracing enabled:
RUST_LOG=debug
Handler Traits
Handler traits (TellHandler, AskHandler, WeakTellHandler, WeakAskHandler) enable unified management of different actor types handling the same message in a single collection. See the Handler Traits Documentation for details.
Further Information
For more detailed questions and answers, please see the FAQ.
License
This project is licensed under the Apache License 2.0. See the LICENSE-APACHE file for details.