Communication
Actors can communicate in many ways depending on the situation and desired guarantees.
Fire and Forget
The most straightforward way is to send a message with minimal guarantees.
However, it's possible to choose the desired behavior by calling the most appropriate method. All variants can be described by the following template: (try_|unbounded_)send(_to)
.
Methods with the _to
suffix allow to specify a destination address as the first argument. Otherwise, the routing subsystem will be used.
The prefix describes what should happen if the destination mailbox is full:
Syntax | Error cases | Description |
---|---|---|
send().await | Closed | Blocks until a destination mailbox has space for new messages |
try_send() | Full , Closed | Returns Full if the mailbox is full |
unbounded_send() | Closed | Ignores the capacity of the mailbox |
All methods can return Closed
if the destination actor is closed.
The form send().await
is used when desired behavior is backpressure, while try_send()
is for actors with predicted latency, when it's acceptable to lose messages or it can be handled manually. unbounded_send()
should be avoided because it can increase mailboxes unpredictably, leading to OOM.
Examples
#[message]
struct SomeMessage;
// Block if the destination mailbox is full.
ctx.send(SomeMessage).await?;
// Do not care if the target actor is closed or full.
ctx.try_send(SomeMessage)?;
// Forcibly push the message into the mailbox.
ctx.unbounded_send(SomeMessage)?;
// Manually implement backpressure, e.g. store messages.
if let Err(err) = ctx.try_send(SomeMessage) {
let msg = err.into_inner(); // msg: SomeMessage
}
Blocking Request-Response
Some communications between actors require response message being sent back to the sender.
TODO
Examples
#[message(ret = Result<(), DoSomethingRejected>)]
struct DoSomething;
#[message]
struct DoSomethingRejected(String);
TODO
Non-blocking Request-Response
TODO
State
TODO
Examples
TODO
Subscriptions
TODO