Skip to main content

Context

Actors all maintain an internal execution context, or state. This allows an actor to determine its own Address, change mailbox limits, or stop its execution.

Mailbox

All messages go to the actor's mailbox first, then the actor's execution context calls specific message handlers. Mailboxes in general are bounded. The capacity is specific to the context implementation. For the Context type the capacity is set to 16 messages by default and can be increased with Context::set_mailbox_capacity().

struct MyActor;

impl Actor for MyActor {
type Context = Context<Self>;

fn started(&mut self, ctx: &mut Self::Context) {
ctx.set_mailbox_capacity(1);
}
}

let addr = MyActor.start();

Remember that this doesn't apply to Addr::do_send(M) which bypasses the Mailbox queue limit, or AsyncContext::notify(M) and AsyncContext::notify_later(M, Duration) which bypasses the mailbox entirely.

Getting your actors Address

An actor can view its own address from its context. Perhaps you want to requeue an event for later, or you want to transform the message type. Maybe you want to respond with your address to a message. If you want an actor to send a message to itself, have a look at AsyncContext::notify(M) instead.

To get your address from the context you call Context::address(). An example is:

struct MyActor;

struct WhoAmI;

impl Message for WhoAmI {
type Result = Result<actix::Addr<MyActor>, ()>;
}

impl Actor for MyActor {
type Context = Context<Self>;
}

impl Handler<WhoAmI> for MyActor {
type Result = Result<actix::Addr<MyActor>, ()>;

fn handle(&mut self, msg: WhoAmI, ctx: &mut Context<Self>) -> Self::Result {
Ok(ctx.address())
}
}

let who_addr = addr.do_send(WhoAmI{});

Stopping an Actor

From within the actors execution context you can choose to stop the actor from processing any future Mailbox messages. This could be in response to an error condition, or as part of program shutdown. To do this you call Context::stop().

This is an adjusted Ping example that stops after 4 pings are received.

impl Handler<Ping> for MyActor {
type Result = usize;

fn handle(&mut self, msg: Ping, ctx: &mut Context<Self>) -> Self::Result {
self.count += msg.0;

if self.count > 5 {
println!("Shutting down ping receiver.");
ctx.stop()
}

self.count
}
}

#[actix_rt::main]
async fn main() {
// start new actor
let addr = MyActor { count: 10 }.start();

// send message and get future for result
let addr_2 = addr.clone();
let res = addr.send(Ping(6)).await;

match res {
Ok(_) => assert!(addr_2.try_send(Ping(6)).is_err()),
_ => {}
}
}