pub trait Actor: Send + 'static {
type Event: Event + Send;
// Provided methods
fn handle_event(
&mut self,
envelope: &Envelope<Self::Event>,
) -> impl Future<Output = Result<()>> + Send { ... }
fn step(&mut self) -> impl Future<Output = Result<StepAction>> + Send { ... }
fn on_start(&mut self) -> impl Future<Output = Result<()>> + Send { ... }
fn on_shutdown(&mut self) -> impl Future<Output = Result<()>> + Send { ... }
fn on_error(&self, error: Error) -> Result<()> { ... }
}Expand description
Core trait implemented by user-defined actors.
Actors are independent units that encapsulate state and process events sequentially. Each actor has its own mailbox (channel) and processes one event at a time, eliminating the need for locks or shared state synchronization.
§Core Methods
handle_event- Process incoming events (reactive)step- Perform periodic work or produce events (proactive)
§Lifecycle Hooks
on_start- Called once before the event loop startson_shutdown- Called once after the event loop stopson_error- Handle errors (swallow or propagate)
§Context (Optional)
Actors that need to send events or stop themselves should store a Context<E>
received from their factory function. Pure event consumers don’t need context:
// Pure consumer - no context needed
struct Logger;
impl Actor for Logger { /* ... */ }
// Producer - stores context to send events
struct Producer { ctx: Context<MyEvent> }§Ergonomics
Methods return futures but can be implemented as async fn directly.
No #[async_trait] macro is required.
See also: Context, Supervisor, Envelope.
Required Associated Types§
Provided Methods§
Sourcefn handle_event(
&mut self,
envelope: &Envelope<Self::Event>,
) -> impl Future<Output = Result<()>> + Send
fn handle_event( &mut self, envelope: &Envelope<Self::Event>, ) -> impl Future<Output = Result<()>> + Send
Handle a single incoming event.
Receives the full Envelope containing both the event payload and metadata.
Use envelope.event() for pattern matching, or access envelope.meta for
sender information and correlation IDs.
§Example
async fn handle_event(&mut self, envelope: &Envelope<Self::Event>) -> Result<()> {
match envelope.event() {
MyEvent::Foo(x) => self.handle_foo(x).await,
MyEvent::Bar => {
// Access metadata when needed
println!("Bar from {}", envelope.meta.actor_name());
Ok(())
}
}
}Called for every event routed to this actor. Return Ok(()) when
processing succeeds, or an error to signal failure. Use Context::send
to emit follow-up events as needed.
Sourcefn step(&mut self) -> impl Future<Output = Result<StepAction>> + Send
fn step(&mut self) -> impl Future<Output = Result<StepAction>> + Send
Optional periodic work or event production.
Returns a StepAction to control when step runs again:
| Action | Behavior |
|---|---|
StepAction::Continue | Run step again immediately |
StepAction::Yield | Yield to runtime, then run again |
StepAction::AwaitEvent | Pause until next event arrives |
StepAction::Backoff(Duration) | Sleep, then run again |
StepAction::Never | Disable step permanently (default) |
§Common Patterns
Time-Based Producer (polls periodically):
async fn step(&mut self) -> Result<StepAction> {
self.ctx.send(HeartbeatEvent).await?;
Ok(StepAction::Backoff(Duration::from_secs(5)))
}External Event Source (driven by I/O):
async fn step(&mut self) -> Result<StepAction> {
let frame = self.websocket.read().await?;
self.ctx.send(WebSocketEvent(frame)).await?;
Ok(StepAction::Continue)
}Pure Event Processor (no step logic needed):
async fn step(&mut self) -> Result<StepAction> {
Ok(StepAction::Never) // Default behavior
}§Default Behavior
Returns StepAction::Never, making the actor purely event-driven.
Sourcefn on_start(&mut self) -> impl Future<Output = Result<()>> + Send
fn on_start(&mut self) -> impl Future<Output = Result<()>> + Send
Lifecycle hook called once before the event loop starts.
Equivalent to:
async fn on_start(&mut self) -> Result<()>;Sourcefn on_shutdown(&mut self) -> impl Future<Output = Result<()>> + Send
fn on_shutdown(&mut self) -> impl Future<Output = Result<()>> + Send
Lifecycle hook called once after the event loop stops.
Equivalent to:
async fn on_shutdown(&mut self) -> Result<()>;Sourcefn on_error(&self, error: Error) -> Result<()>
fn on_error(&self, error: Error) -> Result<()>
Called when an error is returned by handle_event or step.
Return Ok(()) to swallow the error and continue processing,
or Err(error) to propagate and stop the actor.
§Default Behavior
By default, all errors propagate (actor stops). Override this to implement custom error handling, logging, or recovery logic.
§Example
use maiko::{Actor, Error, Event, Result};
fn on_error(&self, error: Error) -> Result<()> {
eprintln!("Actor error: {}", error);
Ok(()) // Swallow and continue
}Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.