Lanes and order
One subscription consumes one queue on one channel; workers(n, by_key) spreads its deliveries
over lanes keyed by a header.
The diagram as text
- Queue orders one consumer of this service → Subscription channel a prefetch window of unacknowledged deliveries: pushed
- Subscription channel a prefetch window of unacknowledged deliveries → LapinSubscriber stream one delivery at a time
- LapinSubscriber stream one delivery at a time → workers(2, by_key) lane = hash of the amqp-partition-key header: one at a time
- workers(2, by_key) lane = hash of the amqp-partition-key header → Lane 1 keys a and c, each in order
- workers(2, by_key) lane = hash of the amqp-partition-key header → Lane 2 key b, in order
- On the server instead: a consistent-hash exchange spreads keys over queues, a subscription each
A subscription's stream yields one delivery at a time, in the order the queue pushed them. Without
workers, one loop runs the handler for each delivery in turn, so the queue's order holds and
nothing runs side by side. The prefetch window decides how many deliveries wait in the service
meanwhile.
workers(n, by_key) runs n lanes. A delivery goes to the lane its key hashes to, and a lane runs
its deliveries in order. The key is the
amqp-partition-key header, which the producer sets.
AMQP does not read it: it is a convention between the producer and this crate. A delivery without
the header has no key, and such deliveries rotate over the lanes.
Lanes need a window wider than one. With a prefetch of 1 the queue pushes the next delivery only after the last one settles, and the lanes take turns.
The order a lane keeps is the order inside one consumer. Two instances of the service on one
queue are two competing consumers, and the queue spreads the deliveries of one key over both.
RabbitMQ's single active consumer (x-single-active-consumer), a queue argument set with
argument, lets one consumer read the queue at a
time.
The consistent-hash exchange moves the same idea to the server. It spreads the routing keys over several queues, and each queue gets a subscription of its own. One key goes to one queue in normal operation, so its order holds across instances while each queue has one consumer.
A batch handler takes what the queue has already pushed, up to the size the mount site names, so a batch is often smaller than that size.