1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use *;
;
;
/// This examples demonstrates `xtra`'s feature of backpressure when waiting for the result of a handler asynchronously.
///
/// Backpressure allows an actor to throttle the sending of new messages by putting a limit on how many messages can be queued in the mailbox at once.
/// To demonstrate backpressure we set up the following environment:
///
/// 1. Single-threaded tokio executor: This ensures that only one task can run at any time.
/// 2. Call `detach` on the [`SendFuture`](xtra::SendFuture) returned by [`Address::send`]: The actor needs to be busy working off messages and thus we cannot synchronously wait for the result.
/// 3. Print "Greeting world!" to stdout before we dispatch a message.
/// 4. Print "Hello world!" upon executing the handler.
///
/// By varying the `mailbox_capacity` and observing the output on stdout, we can see the effects of backpressure:
///
/// ## `mailbox_capacity = Some(0)`
///
/// A `mailbox_capacity` of `Some(0)` will yield `Pending` on the `SendFuture` until the actor is actively requesting the next message from its event-loop.
/// We will thus see a fairly **interleaved** pattern of:
///
/// - "Greeting world!"
/// - "Hello world!"
///
/// This makes sense because the next "Greeting world!" can only be printed once the `SendFuture` is complete which only happens as soon as the actor is ready to take another message which in turn means it is done with processing the current message.
///
/// ## `mailbox_capacity = Some(N)`
///
/// Setting `mailbox_capacity` to `Some(N)` allows us to dispatch up to `N` message to the actor before the returned `SendFuture` returns `Pending`.
/// We can observe this by seeing N+1 blocks of "Greeting world!".
///
/// The task for dispatching messages can dispatch N messages without yielding `Pending`. Due to the single-threaded executor, nothing else is executing during that time.
/// Once the dispatching task yields `Pending`, the runtime switches to the actor's task and processes all queued messages. An empty mailbox will yield `Pending` and the
/// entire dance starts again.
///
/// ## `mailbox_capacity = None`
///
/// A `mailbox_capacity` of `None` creates an interesting output: We only see "Greeting world!" messages.
/// This is easily explained though. `None` creates an unbounded mailbox, meaning there is no artificial upper limit to how many messages we can queue.
///
/// The example ends after the loop and thus, the runtime is immediately destroyed after which means none of the queue handlers ever get to actually execute.
async