This Page is Work In Progress
Introduction
For Qpid for Java version 6.2 we removed the queuerunner which was responsible for assigning messages from the queue to consumers and instead moved to a model where the consumers pull messages from the queue (QPID-7514).
This page is to explain how the new model works, what benefits it brings, what corner cases to think of, and general reasoning behind the implementation.
Why Remove Queuerunner?
The problems with queuerunner were manifold
- unclear threading model
This lead to hard to test code with many sleeps and sporadic test failures - over-reliance on StateChangeListeners
Made the code hard to debug and reason about
High-level Overview
The main players are
- Queue
- QueueConsumerManager
- ConsumerTarget
- (Queue-)Consumers
The ConsumerTarget is the broker-side representation of a consuming client. Due to multi-queue consumers a ConsumerTarget has one or more Consumers associated with one queue each.
The responsibility of the Queue is to notify the Consumers when there is work for them (i.e., messages the consumer is interested in).
The Consumers responsibility is to notify the Queue when it is ready to do some work and when the time has come to pull messages of the queue and process them (i.e. send them to the consuming client).
Consumers are always invoked from the consuming connection's IO-Thread whereas the Queue might be invoked from different threads (producing connection's IO-Thread, Housekeeping thread for held or TTLed messages, a consuming connection's IO-Thread in case for message reject).
Simple Flow
- Message arrives on the Queue
- The Queue notifies some interested Consumers that there is work to be done
- The Consumers notify their ConsumerTarget that they would like to do work
- The ConsumerTargets notify their Session that they would like to do work
- The Sessions notify their Connections that they would like to do work
- The Connections schedule themselves
- The Scheduler kicks off a IO-Thread to process the work of a Connection
- The Connection iterates over its Sessions that want to do work
- The Sessions iterate over its ConsumerTargets that want to do work
- The ConsumerTargets iterate over its Consumers that want to do work
- The Consumer tries to pulls a message from the Queue
- If successful the message is put on the IO-buffer to be sent down the wire
Design Goals
- Avoid spurious wake-ups
- Reduce delay incurred by wake-ups
- Ensure some level of fairness between consumers
Corner Cases and Things to Remember
- Multi-Queue consumers
- consumer priorities
- out-of-order queues
- queue browsers
- fairness