Skip to main content

Actor

Trait Actor 

Source
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 starts
  • on_shutdown - Called once after the event loop stops
  • on_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§

Source

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.

Source

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:

ActionBehavior
StepAction::ContinueRun step again immediately
StepAction::YieldYield to runtime, then run again
StepAction::AwaitEventPause until next event arrives
StepAction::Backoff(Duration)Sleep, then run again
StepAction::NeverDisable 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.

Source

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<()>;
Source

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<()>;
Source

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.

Implementors§