Assignment 04. Safe Inventory and Idempotent Payment Saga
Week 8 · Assignment brief from the course outline; submission and evaluation results have not been recorded.
Dependency: Extends A3 event-driven checkout
Scenario and assignment objective
Two customers race for the final item; repeated checkout requests or broker messages must not result in overselling or duplicate simulated charges.
Required system features
- Restaurant Service owns stock inventory and atomic reservation operation.
- POST /orders supports Idempotency-Key; repeated same key/payload yields same logical order.
- Payment worker stores unique charge record by idempotency key or order_id; duplicates have no second effect.
- Orchestrate reserve inventory -> process payment -> confirm, or compensate reservation on failure.
- Persist Saga execution states; reject invalid state transitions and reconcile interrupted workflows.
- Implement minimal outbox or explicit reconciliation job to address A3 DB/publish dual-write gap.
Implementation guide - suggested steps
- Add inventory table with stock and reservation records to Restaurant data ownership.
- Perform conditional stock update with an atomic WHERE available >= quantity check inside a transaction.
- Create idempotency ledger with UNIQUE key and stored response; detect same key with different payload.
- Add Saga state machine to Order; send reserve, pay, confirm or release commands/events.
- Persist compensation status; ensure retries of release/reserve are idempotent.
- Create fault-injection tests for concurrently competing orders, duplicate event and payment failure.
Hints (not complete solutions)
- Use UPDATE ... SET stock=stock-? WHERE item_id=? AND stock>=? and check affected row count.
- A unique constraint and transaction are stronger than an in-memory if statement for two Order replicas.
- Compensation is a new business action, not a rollback of all service databases.
- Keep a processed_events table keyed by event_id to make message redelivery safe.
API / data contracts
- POST /orders carries Idempotency-Key header; conflict on key reused with different payload is 409.
- Restaurant exposes reserve/release commands with reservation_id, so compensation can be retried.
Mandatory verification and failure experiments
- 20 concurrent reservations for stock=1 -> at most one success; stock never negative.
- Repeat same order and payment request -> one order and one simulated charge.
- Force payment failure and verify inventory restored and final CANCELLED state.
- Crash after local DB write but before publish; outbox/reconciliation completes workflow.
Required individual submission
- Database migrations, Saga state chart, idempotency rules, atomic reservation tests.
- Failure log showing compensation, recovery explanation and revised README.
Acceptance checklist
- No oversell or double simulated charge under repeat/concurrent tests.
- Saga compensation and restarted-workflow recovery demonstrated.
- Dual-write recovery mechanism documented and exercised.
Marks: 8 / 40 lab marks. Use the common rubric: implementation 40%, tests 25%, fault experiment 20%, documentation/viva 15%.