SproutStackSproutStack home
SeniorEvent-driven

Orders span payment, restaurant and courier

A synchronous chain of calls needs manual fixes whenever a step fails halfway.

The setup today

The order service calls payment (capture the charge immediately), then the restaurant (accept or reject), then dispatch (assign a courier), in one request. If a later step fails, support staff refund and cancel by hand.

Current configuration

placeOrder():
  payment.capture(amount)       # money taken now
  restaurant.requestAccept()    # may reject, may time out
  dispatch.assignCourier()      # may find no courier

What you know

  • Restaurants reject about 3% of orders; no courier is found for about 0.5%.
  • Support processes hundreds of manual refunds a week.

The new requirement

Failures must be handled automatically and safely: no manual refunds, no customer charged for an order that is not delivered, and a clear record of what happened to every order. There is no distributed transaction across these services or the payment provider.

Make the call

2 questions · first-try answers earn the most XP

1. Which design fits?
2. The refund compensation times out, and the orchestrator retries it. What must be true?
What a strong answer also covers
  • Persist the saga's state at every step, so it resumes after a crash instead of starting over.
  • Give each step a timeout and decide what a timeout means (for a restaurant: treat as reject after N minutes).
  • Orchestration is easier to follow and monitor for a core flow; choreography suits loosely coupled reactions.
  • Track business metrics per step: acceptance time, compensation rate, sagas stuck in each state.

The background

More drills