|
2 | 2 |
|
3 | 3 | ## Simulation Stages
|
4 | 4 |
|
5 |
| -Simulation activities are broken down into four stages: |
6 |
| -1. Simulation Event: an action that the simulator should execute, |
7 |
| - produced from the user-provided description of desired activities. |
| 5 | +Simulation activities are broken down into four stages: |
| 6 | + |
| 7 | +1. Simulation Event: an action that the simulator should execute, |
| 8 | + produced from the user-provided description of desired activities. |
8 | 9 | 2. Simulation Output: the output of executing an simulation event. Note
|
9 |
| - that this is not the final outcome of the event, as the event itself |
| 10 | + that this is not the final outcome of the event, as the event itself |
10 | 11 | may take a non-trivial amount of time to complete.
|
11 |
| -3. Result Tracking: per-output tracking of the final outcome of the |
| 12 | +3. Result Tracking: per-output tracking of the final outcome of the |
12 | 13 | simulation event.
|
13 |
| -4. Simulation Result: recording of the final result as provided by |
| 14 | +4. Simulation Result: recording of the final result as provided by |
14 | 15 | result tracking, which is a final result of the simulation.
|
15 | 16 |
|
16 | 17 | ## Activity Generation
|
| 18 | + |
17 | 19 | The simulator uses tokio's asynchronous multi-producer, single-consumer
|
18 |
| -channels to implement a consume/producer architecture to produce, |
19 |
| -execute and track simulation events. Stages of the simulation |
20 |
| -communicate by passing the _receiver_ for the next stage to the |
21 |
| -consumer from the previous stage, allowing each stage to pass it's |
| 20 | +channels to implement a consume/producer architecture to produce, |
| 21 | +execute and track simulation events. Stages of the simulation |
| 22 | +communicate by passing the _receiver_ for the next stage to the |
| 23 | +consumer from the previous stage, allowing each stage to pass it's |
22 | 24 | output on to the next one.
|
23 | 25 |
|
24 | 26 | ```
|
@@ -52,38 +54,25 @@ output on to the next one.
|
52 | 54 | ```
|
53 | 55 |
|
54 | 56 | ### Shutdown
|
55 |
| -To ensure that all tasks shutdown on completion (or failure) of the |
56 |
| -simulation, we relay on the following: |
57 |
| -1. [Triggered](https://docs.rs/triggered/latest/triggered): a `Trigger` |
58 |
| - that can be used to inform threads that it's time to shut down, and |
59 |
| - a `Listener` that propagates this signal. |
60 |
| -2. Channel mechanics: if all of the senders for a channel have been |
61 |
| - dropped (in our context, all of the producers have exited) then the |
62 |
| - corresponding receiving channel will error out on receiving. Likewise, |
63 |
| - if the receiving channel is dropped, the sending channels will error |
64 |
| - out. |
65 |
| - |
66 |
| -All events are handled in a `tokio::select` to allow waiting on |
67 |
| -multiple asynchronous tasks at once. These selects should be `biased` |
68 |
| -on the exit case (ie, the `Listener` being triggered) so that we |
69 |
| -prioritize exit above generating more events. |
70 | 57 |
|
71 |
| -Practically, this means that we're handling the various shutdown |
72 |
| -scenarios in the following way: |
73 |
| - |
74 |
| -1. Consumer error: |
75 |
| - - Receiving channel is dropped on consumer exit. |
76 |
| - - Sending channels used by producers will error out. |
77 |
| - - Producers will trigger shutdown. |
78 |
| - - Listening producers will exit. |
79 |
| - |
80 |
| -2. Producer error: |
81 |
| - - Producers will trigger shutdown. |
82 |
| - - Listening producers will exit. |
83 |
| - - Once all producers have exited, the consuming channel's receiver |
84 |
| - will error out causing it to exit. |
85 |
| - |
86 |
| -3. Miscellaneous tasks: |
87 |
| - - Trigger shutdown on exit. |
88 |
| - - Listen for shutdown from other errors. |
| 58 | +To ensure that all tasks shutdown on completion (or failure) of the |
| 59 | +simulation, we relay on the following: |
89 | 60 |
|
| 61 | +1. [Triggered](https://docs.rs/triggered/latest/triggered): a `Trigger` |
| 62 | + that can be used to inform threads/tasks that it's time to shut down, |
| 63 | + and a `Listener` that propagates this signal. |
| 64 | +2. The (`Trigger`, `Listener`) pair are used with channels: if a channel |
| 65 | + errors out across `send()` or `recv()`, shutdown is triggered. There is |
| 66 | + no reliance on channel mechanics, i.e. errors generated when all senders |
| 67 | + are and/or a receiver is dropped. |
| 68 | +3. All events are handled in a `tokio::select` to allow waiting on |
| 69 | +multiple asynchronous tasks at once. These selects should be `biased` |
| 70 | +on the exit case (ie, the `Listener` being triggered) so that we |
| 71 | +prioritize exit above generating more events. |
| 72 | +4. Additionally, we `select!` on shutdown signal on `send()`/`recv()` |
| 73 | +for all channels to guarantee this: |
| 74 | + - A task's receiver exiting while one or more corresponding senders |
| 75 | + (in different tasks) are actively sending, doesn't result in the |
| 76 | + sending tasks erroring due to channel `SendError`. Any sender's |
| 77 | + inability to `send()` due to a dropped receiver triggers a clean |
| 78 | + shutdown across all listening tasks. |
0 commit comments