22. Message Queues
22.7 How does ordering work?
At the bank: One counter serves tokens in order. But with ten counters, token 48 might finish before token 47. Usually fine. But if your deposit and your withdrawal go to different counters, the withdrawal might be tried first and bounce.
In the system: A queue with many consumers doesn't preserve order: messages are handed out in order, but finish in whatever order the workers happen to finish. In the chapter's code, an order's "placed, paid, packed, shipped" events handed to 8 parallel workers come out scrambled.
Most of the time you only need order per key: all events for order 881 in order; order 881 and order 882 can interleave freely. The standard fix is partitioning by key:
Figure: same key, same partition, one consumer at a time: order kept per key, parallel across keys.
- Kafka: messages with the same key go to the same partition; a partition is read by one consumer in a group, in order.
- SQS FIFO: messages with the same message group ID are delivered in order, one batch at a time.
- RabbitMQ: a single consumer per queue, or consistent-hash routing to several queues.
In the chapter's code, partitioning by order ID keeps every order's steps in sequence.
Costs and alternatives:
- A slow or stuck message blocks its partition (or group) until it's handled or dead-lettered.
- Throughput per key is limited to one consumer.
- Often you can avoid needing order: include a version or timestamp and ignore older updates (Chapter 19's versioned index updates), or make the consumer handle "paid before placed" by checking state.
Memory code: "Same key, same line, same clerk: order kept where it matters."