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
Actor System
- Minimalist Design: Focuses on core actor model primitives with a clean API
- Tokio-Native: Built for the
tokioasynchronous runtime - Actor Derive Macro:
#[derive(Actor)]for simple actors that don't need complex initialization
Message Passing
| Method | Description |
|---|---|
ask / ask_with_timeout |
Send a message and asynchronously await a reply |
tell / tell_with_timeout |
Send a message without waiting for a reply (fire-and-forget) |
blocking_ask / blocking_tell |
Blocking versions for tokio::task::spawn_blocking contexts |
- Macro-Assisted Handlers:
#[message_handlers]attribute macro with#[handler]method attributes for automatic message handling
Actor Lifecycle
Three well-defined hooks for managing actor behavior:
on_start: Initializes the actor's state (required)on_run: Main execution logic, runs concurrently with message handling (optional)on_stop: Cleanup before termination, withkilledflag for graceful vs immediate (optional)
Supports graceful termination (stop()) and immediate termination (kill()), with ActorResult enum representing lifecycle outcomes.
Type Safety
- Compile-Time Safety:
ActorRef<T>ensures message handling consistency and prevents type-related runtime errors - Handler Traits:
TellHandler<M>andAskHandler<M, R>enable unified management of different actor types in a single collection - Actor Control Traits:
ActorControlandWeakActorControlprovide type-erased lifecycle management - Only
SendRequired: Actor structs only needSendtrait (notSync), enabling interior mutability types likestd::cell::Cell
Observability
- Optional Tracing: Built-in support via
tracingfeature flag for actor lifecycle events, message handling, and performance metrics - Metrics Support: Optional
metricsfeature for monitoring message counts, processing times, and actor uptime
Why rsActor?
Focused Scope
Unlike broader frameworks like Actix, rsActor specializes exclusively in local, in-process actor systems. This focused approach eliminates complexity from unused features like remote actors or clustering, resulting in a cleaner API and smaller footprint.
Key Advantages
- Simplicity First: Minimal API surface with sensible defaults
- Type-Safe by Default:
ActorRef<T>ensures compile-time message validation with zero runtime overhead - Flexible Type Erasure: Handler traits enable managing heterogeneous actor collections without sacrificing type safety
- Production-Ready Observability: Integrated tracing and metrics support
- Mutex-Free Design: No shared locks between actors - state is isolated within each actor
Getting Started
1. Add Dependency
[]
= "0.12" # Check crates.io for the latest version
# Optional: Enable tracing support for detailed observability
# rsactor = { version = "0.12", 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 concepts with
#[message_handlers]macro - actor_with_timeout - Using timeouts for actor communication
- actor_async_worker - Inter-actor communication with async tasks
- actor_blocking_task - Using blocking APIs with actors
- dining_philosophers - Classic concurrency problem implementation
- weak_reference_demo - Working with weak actor references and lifecycle
- handler_demo - Using handler traits for unified actor management
- ask_join_demo - Using
ask_joinfor CPU/IO-bound operations - metrics_demo - Actor performance monitoring (requires
metricsfeature) - tracing_demo - Structured logging and actor lifecycle tracing
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.12", = ["tracing"] }
= "0.1"
= "0.3"
All examples include tracing support. Here's the recommended initialization pattern:
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.
Actor Control Traits
Actor control traits (ActorControl, WeakActorControl) provide type-erased lifecycle management for different actor types in a single collection. Handler traits provide as_control() and as_weak_control() methods to access lifecycle operations.
Documentation
- Debugging Guide - Error handling, dead letter tracking, and troubleshooting
- Metrics Guide - Actor performance monitoring
- Tracing Guide - Detailed observability with tracing
- FAQ - Common questions and answers
Contributing
We welcome contributions! Here's how to get started:
Development Setup
# Run tests
# Run examples
# With tracing
RUST_LOG=debug
Code Quality
Before submitting a PR, ensure:
Ways to Contribute
- Bug reports and fixes
- Documentation improvements
- New examples
- Performance optimizations
- Feature requests
Claude Code Skills
rsActor provides Claude Code skills to help AI assistants write correct rsactor code.
Installation
# Global installation (recommended)
|
# Project-local installation
|
Available Skills
- rsactor-actor: Create new actors with proper patterns
- rsactor-handler: Add message handlers to existing actors
- rsactor-guide: API reference and troubleshooting guide
License
This project is licensed under the Apache License 2.0. See the LICENSE-APACHE file for details.