More than one reporter
What you want to do
The shop's customer service desk wants to hear about every order that failed, and where it failed, and about nothing else. You want the desk to read the same record of who decided what as the log, for a purpose of its own, without changing the log or any step.
The code
The desk is a second reporter. Of all the events it receives, it keeps only journey_failed, and ignores the rest.
/// The customer service desk: of all the events of a journey, it keeps only a failed journey's.
#[derive(Default)]
struct Desk;
impl Reporter for Desk {
fn report(&mut self, event: &Event) -> Result<(), Error> {
if let EventBody::JourneyFailed { step, .. } = &event.body {
println!("desk: an order failed at {step}");
}
Ok(())
}
}The workflow lists both reporters, the log first:
/// The shop's workflow: it charges, then ships, and every journey goes to the log and the desk.
#[workflow(name = "orders", reporters = [Log, Desk])]
#[with_step(Charge, name = "charge")]
#[with_step(Ship, name = "ship")]
struct Orders;The log and the shipping are chapter 9's, the charge is chapter 7's, and the shop runs Ann's and Gil's orders again. It prints:
Ann's order:
log #1 journey_started order, price, weight
log #2 attempt_started charge
log #3 service_provided charge gets payments from bank, a ch10_more_than_one_reporter::Bank
the bank charges 40 for order A-1
log #4 step_succeeded charge
log #5 contribution_committed receipt
log #6 attempt_started ship
log #7 service_provided ship gets carrier from main_carrier, a ch10_more_than_one_reporter::MainCarrier
the carrier books order A-1
log #8 step_info ship: the parcel leaves with receipt R-A-1
log #9 step_succeeded ship
log #10 contribution_committed tracking
log #11 journey_succeeded
the journey succeeded, with receipt R-A-1 and tracking T-A-1
Gil's order:
log #1 journey_started order, price, weight
log #2 attempt_started charge
log #3 service_provided charge gets payments from bank, a ch10_more_than_one_reporter::Bank
the bank charges 45 for order A-7
log #4 step_succeeded charge
log #5 contribution_committed receipt
log #6 attempt_started ship
log #7 service_provided ship gets carrier from main_carrier, a ch10_more_than_one_reporter::MainCarrier
the carrier books order A-7
log #8 step_failed ship: too-heavy
log #9 step_given_up ship
log #10 journey_failed ship
desk: an order failed at ship
the journey failed, with receipt R-A-7 and tracking noneHow it works
- Every reporter receives every event. For each journey, the executor makes one dispatcher, which delivers the journey's events to its reporters: it hands each event, in order, to each reporter in turn. One stream fans out to every reporter, and each decides on its own what to do with it. The log writes a line for every event; the desk ignores all but one kind. Ann's journey doesn't fail, so the desk says nothing about it, though it received all eleven of her journey's events.
- The order of the list is the order of delivery. The dispatcher Itinera uses unless told otherwise calls the reporters in the order the workflow lists them. That's why, for Gil's journey, the log writes
journey_failedbefore the desk hears of it. - The journey waits for every reporter. An event is delivered to every reporter before the journey goes on, so the desk had Gil's failure before
runreturned. A reporter that takes its time slows every journey it reports, so a reporter that sends events to another system should be quick about it. - Adding a reporter changes nothing else. The desk was added with one word in the workflow's declaration. No step, no service and no other reporter changed, and the log prints what it printed before, but for the program's name at the start of each implementation. Steps report what happened; reporters decide who hears about it.
- Each reporter is its own. Every journey gets one of each listed reporter, made anew with
Default, as the log is. A reporter can keep what it receives in its own fields, and nothing it keeps is shared with another reporter or another journey.
The desk now hears about every failed order, but look at what it says: "an order failed at ship". Which order? Each event carries the journey's ID, but nothing names the journeys, so every journey gets a new random one, meaningless to the people at the desk.
Outcomes
We have shown how several reporters each get every event of a journey, and keep what they need.
| The usual way | With Itinera |
|---|---|
| A new audience for what the code does, such as a support desk, usually means adding a call to it wherever something it cares about happens. | A new audience is one more reporter listed on the workflow, and it receives every event without changing a step. |
| A second log is often written apart from the first, so the two can tell different stories about the same order. | Every reporter receives the same events in the same order, so the log and the desk tell one story of who decided what. |