Actor Traits¶
This section documents the core traits that define actor behavior in airssys-rt.
Actor Trait¶
The fundamental trait that all actors must implement.
#[async_trait]
pub trait Actor: Send + Sync + 'static {
/// The type of messages this actor handles
type Message: Message;
/// The error type for actor operations
type Error: Error + Send + Sync + 'static;
/// Handle an incoming message (REQUIRED)
async fn handle_message<B: MessageBroker<Self::Message>>(
&mut self,
message: Self::Message,
context: &mut ActorContext<Self::Message, B>,
) -> Result<(), Self::Error>;
/// Lifecycle hook: called before actor starts (optional)
async fn pre_start<B: MessageBroker<Self::Message>>(
&mut self,
context: &mut ActorContext<Self::Message, B>,
) -> Result<(), Self::Error> {
Ok(())
}
/// Lifecycle hook: called when actor stops (optional)
async fn post_stop<B: MessageBroker<Self::Message>>(
&mut self,
context: &mut ActorContext<Self::Message, B>,
) -> Result<(), Self::Error> {
Ok(())
}
/// Error handler: return supervision decision (optional)
async fn on_error<B: MessageBroker<Self::Message>>(
&mut self,
error: Self::Error,
context: &mut ActorContext<Self::Message, B>,
) -> ErrorAction {
ErrorAction::Stop // Default: stop the actor
}
}
Required Methods¶
handle_message: Process incoming messages. This is the core method where your actor's business logic lives.
Optional Methods¶
-
pre_start: Called once before the actor starts processing messages. Use for initialization (e.g., connecting to databases, loading resources). -
post_stop: Called when the actor stops. Use for cleanup (e.g., closing connections, releasing resources). -
on_error: Called whenhandle_messagereturns an error. Return anErrorActionto control supervision behavior.
Example¶
See examples/actor_basic.rs for a complete actor implementation.
use airssys_rt::{Actor, ActorContext, Message, ErrorAction};
use async_trait::async_trait;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct MyMessage {
data: String,
}
impl Message for MyMessage {
const MESSAGE_TYPE: &'static str = "my_message";
}
struct MyActor {
state: i32,
}
#[async_trait]
impl Actor for MyActor {
type Message = MyMessage;
type Error = std::io::Error;
async fn pre_start<B: MessageBroker<Self::Message>>(
&mut self,
context: &mut ActorContext<Self::Message, B>,
) -> Result<(), Self::Error> {
println!("Actor {} starting", context.address().name().unwrap_or("anonymous"));
Ok(())
}
async fn handle_message<B: MessageBroker<Self::Message>>(
&mut self,
message: Self::Message,
context: &mut ActorContext<Self::Message, B>,
) -> Result<(), Self::Error> {
println!("Processing: {}", message.data);
self.state += 1;
context.record_message();
Ok(())
}
async fn on_error<B: MessageBroker<Self::Message>>(
&mut self,
error: Self::Error,
_context: &mut ActorContext<Self::Message, B>,
) -> ErrorAction {
eprintln!("Error: {}", error);
ErrorAction::Stop // Stop on error (can customize based on error type)
}
}
Child Trait¶
Trait for entities that can be supervised.
#[async_trait]
pub trait Child: Send + Sync {
/// Start the child entity
async fn start(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
/// Stop the child entity
async fn stop(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
/// Check the health status
async fn health_check(&self) -> ChildHealth;
}
Note: Actors automatically implement Child via a blanket implementation, so you don't need to implement this manually for actors.
Example (Custom Child)¶
use airssys_rt::supervisor::{Child, ChildHealth};
use async_trait::async_trait;
struct Worker {
id: String,
}
#[async_trait]
impl Child for Worker {
async fn start(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
println!("Worker {} started", self.id);
Ok(())
}
async fn stop(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
println!("Worker {} stopped", self.id);
Ok(())
}
async fn health_check(&self) -> ChildHealth {
ChildHealth::Healthy
}
}
See examples/supervisor_basic.rs for complete usage.
MessageBroker Trait¶
Trait for message routing and pub/sub.
#[async_trait]
pub trait MessageBroker<M: Message>: Clone + Send + Sync + 'static {
type Error: Error + Send + Sync + 'static;
/// Publish a message to all subscribers
async fn publish(&self, envelope: MessageEnvelope<M>)
-> Result<(), Self::Error>;
/// Subscribe to messages for an actor
async fn subscribe(&self, subscriber_id: ActorId)
-> Result<mpsc::Receiver<MessageEnvelope<M>>, Self::Error>;
}
Implementations¶
InMemoryMessageBroker<M>: Default in-memory implementation using channels
Example¶
use airssys_rt::broker::InMemoryMessageBroker;
let broker = InMemoryMessageBroker::<MyMessage>::new();
Mailbox Traits¶
MailboxReceiver¶
#[async_trait]
pub trait MailboxReceiver<M: Message>: Send {
/// Receive next message (blocking)
async fn recv(&mut self) -> Option<MessageEnvelope<M>>;
/// Try to receive message (non-blocking)
fn try_recv(&mut self) -> Result<MessageEnvelope<M>, TryRecvError>;
}
MailboxSender¶
#[async_trait]
pub trait MailboxSender<M: Message>: Clone + Send + Sync {
/// Send a message to the mailbox
async fn send(&self, envelope: MessageEnvelope<M>)
-> Result<(), MailboxError>;
}
Implementations¶
UnboundedMailbox<M>: Unlimited capacity mailboxBoundedMailbox<M>: Fixed capacity mailbox with backpressure
All traits use async_trait for async method support. See the generated Rustdoc (cargo doc --open) for complete trait documentation.