flowon failureon cancelship_order v1examples/order/temporal/order.flow · dandori doc
For an order in the warehouse's system, ask for the payment, have it shipped, and wait for word of the delivery. The warehouse's system keeps the order's state, which moves as rulec's rule order_state says. Written for Temporal: the warehouse's calls are activities dandori writes, and the notice is an activity you write; the carrier's system tells the workflow of the order about the delivery, by the order's id (an event); and an order the shop cancels on the way is cancelled at the warehouse too (on cancel). The loop over the reminders goes on in a new run when its history grows long
flowon failureon cancel| Line | Call | Calls | Retries | Timeout | When it fails | Case after |
|---|---|---|---|---|---|---|
| 61 | order ← get_order(…) | GET https://warehouse.example.com/v1/orders/{id}, observes, idempotent | 3 times every 1 second (busy) | — | busy, timeout, failure → on failure | order: received, paid, shipped, delivered, cancelled |
| 65 | r = notify(…) | a task you write, key | 2 times every 5 seconds (failure, timeout) | — | no_recipient → line 66timeout, failure → on failure | — |
| 68 | order ← get_order(…) | GET https://warehouse.example.com/v1/orders/{id}, observes, idempotent | 3 times every 1 second (busy) | — | busy, timeout, failure → on failure | order: received, paid, cancelled |
| 72 | order ← request_cancel(…) | POST https://warehouse.example.com/v1/orders/{id}/cancellations, sends cancel, key | — | — | conflict → line 73timeout, failure → on failure | order: cancelled |
| 78 | decision = urgency(…) | rule urgency.rule | 2 times, after 1 second and 2 (failure) | — | timeout, failure → on failure | — |
| 79 | order ← request_shipment(…) | POST https://warehouse.example.com/v1/orders/{id}/shipments, sends ship, key | — | — | conflict → line 80timeout, failure → on failure | order: shipped |
| 82 | n = notify(…) | a task you write, key | 2 times every 5 seconds (failure, timeout) | — | no_recipient, timeout, failure → on failure | — |
| 84 | order ← delivered() | event, observes | — | 7 days | timeout → line 85failure → on failure | order: shipped, delivered |
| 99 | order ← request_cancel(…) | POST https://warehouse.example.com/v1/orders/{id}/cancellations, sends cancel, key | — | — | conflict → line 100timeout, failure → line 101 | order: cancelled |
| Line | End | order |
|---|---|---|
| 66 | fail NoContact leaving order | handed over as it is: received, paid, cancelled |
| 74 | fail NotPaid "No payment came in three days" | cancelled |
| 75 | fail Canceled "The order was canceled" | cancelled |
| 76 | fail AlreadyShipped "The order has shipped already" leaving order | handed over as it is: shipped, delivered |
| 80 | fail Canceled "The order was canceled before it shipped" | cancelled |
| 85 | fail DeliveryLate "No word of the delivery in seven days" leaving order | handed over as it is: shipped, delivered |
| 87 | succeed carrier = decision.carrier | delivered |
| 88 | fail DeliveryLate "Still shipped after word of the delivery" leaving order | handed over as it is: shipped, delivered |
| 91 | fail Stopped "Stopped on the way; the order stays in the warehouse's system as it is" leaving order | handed over as it is: not started, or received, paid, shipped, delivered, cancelled |
| 100 | fail ShippedAlready "The warehouse refused to cancel order {order.id}; it may have shipped" leaving order | handed over as it is: shipped, delivered, cancelled |
| 101 | fail CancelFailed "Could not cancel order {order.id} at the warehouse" leaving order | handed over as it is: received, paid, shipped, delivered, cancelled |
| 102 | fail ShippedAlready "Order {order.id} has shipped already" leaving order | handed over as it is: shipped, delivered |
| 102 | on cancel runs to its end, and the workflow ends cancelled | not started, or cancelled |
Pick a step to see what the checker knows there. Pick a scenario on the left to light up the way its run goes; the number beside a step is how often the run passes it.
ship_order v1For an order in the warehouse's system, ask for the payment, have it shipped, and wait for word of the delivery. The warehouse's system keeps the order's state, which moves as rulec's rule order_state says. Written for Temporal: the warehouse's calls are activities dandori writes, and the notice is an activity you write; the carrier's system tells the workflow of the order about the delivery, by the order's id (an event); and an order the shop cancels on the way is cancelled at the warehouse too (on cancel). The loop over the reminders goes on in a new run when its history grows long
order_id: stringcarrier: urgency.carrierexamples/order/temporal/order.floworder ← get_order(…) line 61 61 order <- get_order(id: order_id, expand: "items")
order: not startedGET https://warehouse.example.com/v1/orders/{id}, observes, idempotentbusy, timeout, failure → on failureorder: received, paid, shipped, delivered, cancelled22 task get_order(id: string, expand: string) -> Order 23 http GET "https://warehouse.example.com/v1/orders/{id}" 24 observes 25 idempotent 26 errors busy = 429 27 retry 3 times every 1 second on busy
match order.state line 6363 match order.state 64 received => 69 paid, shipped, delivered, cancelled => break
order: received, paid, shipped, delivered, cancelledr = notify(…) line 6565 let r = notify(order_id: order.id, text: "We are waiting for your payment") 66 on no_recipient => fail NoContact leaving order
order: receivedkeyno_recipient → line 66timeout, failure → on failure43 # The shop's own notice service, called from code you write. 44 task notify(order_id: string, text: string) -> Receipt 45 errors no_recipient 46 key 47 retry 2 times every 5 seconds
fail NoContact line 66 66 on no_recipient => fail NoContact leaving order
order: receivedorder: handed over as it is: received, paid, cancelledwait 1 day line 67 67 wait 1 day
order: receivedorder ← get_order(…) line 68 68 order <- get_order(id: order.id, expand: "items")
order: receivedGET https://warehouse.example.com/v1/orders/{id}, observes, idempotentbusy, timeout, failure → on failureorder: received, paid, cancelled22 task get_order(id: string, expand: string) -> Order 23 http GET "https://warehouse.example.com/v1/orders/{id}" 24 observes 25 idempotent 26 errors busy = 429 27 retry 3 times every 1 second on busy
break line 69 69 paid, shipped, delivered, cancelled => break
order: paid, shipped, delivered, cancelledmatch order.state line 7070 match order.state 71 received => 75 cancelled => fail Canceled "The order was canceled" 76 shipped, delivered => fail AlreadyShipped "The order has shipped already" leaving order 77 paid => pass
order: received, paid, shipped, delivered, cancelledorder ← request_cancel(…) line 7272 order <- request_cancel(id: order.id) 73 on conflict => pass
order: receivedPOST https://warehouse.example.com/v1/orders/{id}/cancellations, sends cancel, keyconflict → line 73timeout, failure → on failureorder: cancelled36 task request_cancel(id: string) -> Order 37 http POST "https://warehouse.example.com/v1/orders/{id}/cancellations" 38 sends cancel 39 errors conflict = 409 40 refused as conflict 41 key
fail NotPaid line 74 74 fail NotPaid "No payment came in three days"
order: cancelledorder: cancelledfail Canceled line 75 75 cancelled => fail Canceled "The order was canceled"
order: cancelledorder: cancelledfail AlreadyShipped line 76 76 shipped, delivered => fail AlreadyShipped "The order has shipped already" leaving order
order: shipped, deliveredorder: handed over as it is: shipped, delivereddecision = urgency(…) line 78 78 let decision = urgency(member: order.member, amount: order.amount)
order: paidurgency.ruletimeout, failure → on failure 5 use rule urgency from "../rules/urgency.rule"
order ← request_shipment(…) line 7979 order <- request_shipment(id: order.id, carrier: decision.carrier) 80 on conflict => fail Canceled "The order was canceled before it shipped"
order: paidPOST https://warehouse.example.com/v1/orders/{id}/shipments, sends ship, keyconflict → line 80timeout, failure → on failureorder: shipped29 task request_shipment(id: string, carrier: urgency.carrier) -> Order 30 http POST "https://warehouse.example.com/v1/orders/{id}/shipments" 31 sends ship 32 errors conflict = 409 33 refused as conflict 34 key
fail Canceled line 80 80 on conflict => fail Canceled "The order was canceled before it shipped"
order: cancelledorder: cancelledmatch decision.urgent line 8181 match decision.urgent 82 true => let n = notify(order_id: order.id, text: "Shipped by next-day delivery") 83 false => pass
order: shippedn = notify(…) line 82 82 true => let n = notify(order_id: order.id, text: "Shipped by next-day delivery")
order: shippedkeyno_recipient, timeout, failure → on failure43 # The shop's own notice service, called from code you write. 44 task notify(order_id: string, text: string) -> Receipt 45 errors no_recipient 46 key 47 retry 2 times every 5 seconds
order ← delivered() line 8484 order <- delivered() 85 on timeout => fail DeliveryLate "No word of the delivery in seven days" leaving order
order: shippedevent, observestimeout → line 85failure → on failureorder: shipped, delivered49 # The carrier's system sends the order as the warehouse has it now to the workflow of the 50 # order when the carrier reports the delivery. 51 task delivered() -> Order 52 event 53 observes 54 timeout 7 days
fail DeliveryLate line 85 85 on timeout => fail DeliveryLate "No word of the delivery in seven days" leaving order
order: shippedorder: handed over as it is: shipped, deliveredmatch order.state line 8686 match order.state 87 delivered => succeed carrier = decision.carrier 88 shipped => fail DeliveryLate "Still shipped after word of the delivery" leaving order
order: shipped, deliveredsucceed carrier = decision.carrier line 87 87 delivered => succeed carrier = decision.carrier
order: deliveredorder: deliveredfail DeliveryLate line 88 88 shipped => fail DeliveryLate "Still shipped after word of the delivery" leaving order
order: shippedorder: handed over as it is: shipped, deliveredend: succeedsThe flow runs to its end, and the workflow succeeds.
on failure line 90Runs when a call fails and nothing at the call handles the error. When it runs to its end, the workflow fails with that error. It comes here from the calls on lines 61, 65, 68, 72, 78, 79, 82 and 84.
fail Stopped line 91 91 fail Stopped "Stopped on the way; the order stays in the warehouse's system as it is" leaving order
order: not started, or received, paid, shipped, cancelledorder: handed over as it is: not started, or received, paid, shipped, delivered, cancelledfails with the same erroron failure runs to its end, and the workflow fails with the error that started it.
on cancel line 95Runs when the workflow is cancelled, from the call or the wait the run is at. When it runs to its end, the workflow ends cancelled.
match order.state line 9696 match order.state 97 none => pass 98 received, paid => 102 shipped => fail ShippedAlready "Order {order.id} has shipped already" leaving order
order: not started, or received, paid, shipped, cancelledorder ← request_cancel(…) line 9999 order <- request_cancel(id: order.id) 100 on conflict => fail ShippedAlready "The warehouse refused to cancel order {order.id}; it may have shipped" leaving order 101 on failure => fail CancelFailed "Could not cancel order {order.id} at the warehouse" leaving order
order: received, paid, shipped, cancelledPOST https://warehouse.example.com/v1/orders/{id}/cancellations, sends cancel, keyconflict → line 100timeout, failure → line 101order: cancelled36 task request_cancel(id: string) -> Order 37 http POST "https://warehouse.example.com/v1/orders/{id}/cancellations" 38 sends cancel 39 errors conflict = 409 40 refused as conflict 41 key
fail ShippedAlready line 100 100 on conflict => fail ShippedAlready "The warehouse refused to cancel order {order.id}; it may have shipped" leaving order
order: shipped, delivered, cancelledorder: handed over as it is: shipped, delivered, cancelledfail CancelFailed line 101 101 on failure => fail CancelFailed "Could not cancel order {order.id} at the warehouse" leaving order
order: received, paid, shipped, delivered, cancelledorder: handed over as it is: received, paid, shipped, delivered, cancelledfail ShippedAlready line 102 102 shipped => fail ShippedAlready "Order {order.id} has shipped already" leaving order
order: shippedorder: handed over as it is: shipped, deliveredends cancelledon cancel runs to its end, and the workflow ends cancelled.
order: not started, or cancelledrepeat at most 3 times line 62 62 repeat at most 3 times
order: received, paid, shipped, delivered, cancelledorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) no_recipient → on no_recipientfail NoContactorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) okorder ← delivered() ok: shippedmatch order.state → shippedfail DeliveryLateorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) failure failure failure → not handled hereon failurefail Stoppedorder ← get_order(…) ok: cancelledrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → cancelledfail Canceledorder ← get_order(…) ok: shippedrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → shipped, deliveredfail AlreadyShippedorder ← get_order(…) ok: deliveredrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → shipped, deliveredfail AlreadyShippedorder ← get_order(…) failure → not handled hereon failurefail Stoppedorder ← get_order(…) busy ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) failure failure failure → not handled hereon failurefail Stoppedorder ← get_order(…) okorder ← get_order(…) ok: receivedorder ← get_order(…) cancelon cancelmatch order.state → noneorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) ok: paidmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) ok: cancelledorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: paidmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) conflict → on conflictfail ShippedAlreadyorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: cancelledmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → cancelledfail Canceledorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) failure → not handled hereon failurefail Stoppedorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedorder ← request_cancel(…) ok: cancelledfail NotPaidorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: shippedorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) okorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) conflict → on conflictfail ShippedAlreadyorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedorder ← request_cancel(…) conflict → on conflictfail NotPaidorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedorder ← request_cancel(…) conflict → on conflictfail NotPaidorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) failure → on failurefail CancelFailedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) ok: receivedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) conflict → on conflictfail Canceledorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) conflict → on conflictfail Canceledorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) failure → not handled hereon failurefail Stoppedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: receivedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) okorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) okorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → falseorder ← delivered() ok: deliveredmatch order.state → deliveredsucceed carrier = decision.carrierorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) failure failure failure → not handled hereon failurefail Stoppedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) failure okorder ← delivered() timeout → on timeoutfail DeliveryLateorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) okorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) cancelon cancelmatch order.state → shippedfail ShippedAlreadyorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) okorder ← delivered() failure → not handled hereon failurefail Stoppedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) okorder ← delivered() ok: receivedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) okorder ← delivered() okorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) okorder ← delivered() ok: shippedorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) okorder ← request_shipment(…) ok: shippedmatch decision.urgent → truen = notify(…) okorder ← delivered() cancelon cancelmatch order.state → shippedfail ShippedAlreadyorder ← get_order(…) ok: paidrepeat at most 3 timesmatch order.state → paid, shipped, delivered, cancelledbreakmatch order.state → paiddecision = urgency(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) ok: cancelledorder ← get_order(…) busy ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedorder ← request_cancel(…) failure → not handled hereon failurefail Stoppedorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedorder ← request_cancel(…) ok: receivedorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedorder ← request_cancel(…) okorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) failure okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedorder ← request_cancel(…) ok: cancelledorder ← get_order(…) ok: receivedrepeat at most 3 timesmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) busy ok: receivedmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedr = notify(…) okwait 1 dayorder ← get_order(…) ok: receivedmatch order.state → receivedorder ← request_cancel(…) cancelon cancelmatch order.state → received, paidorder ← request_cancel(…) ok: received