I look for ordering bugs when data seems to appear in the wrong state. A shipment before an order or a refund before a charge is usually not missing data; it is an ordering rule that the system failed to enforce.
Order needs a scope
When I talk about "Order needs a scope", I am really asking what Ordering does when a message is late, duplicated, or missing.
Global order is expensive and often unnecessary. Most systems need order within a customer, account, order, or partition. Naming that scope keeps the design both correct and practical.
Event log example
I use "Event log example" to keep Ordering grounded in a real system, because abstract patterns are too easy to agree with and too hard to operate.
An order service emits OrderCreated, PaymentCaptured, and OrderShipped. The warehouse consumer must apply them in that order for each order id.
Ordered consumer code
When I show "Ordered consumer code", I want the code in Ordering to reveal the production decision, not just the syntax.
Consumers should apply events only when the next sequence is present:
void apply(OrderEvent event) {
long expected = lastSequence.get(event.orderId()) + 1;
if (event.sequence() != expected) return;
state.apply(event);
lastSequence.put(event.orderId(), event.sequence());
}
The handler applies only the next expected sequence number. Out-of-order events wait instead of corrupting state with a future update.
Sequence diagram: preserve order per order id
The system does not need one order for the whole company. It needs a correct order for this order id.
The ordering contract
- Define the ordering scope before choosing the tool.
- Partition streams by the key that needs ordered handling.
- Make consumers reject impossible transitions.