RabbitMQ has priority queue implementation in the core as of version 3.5.0
. Any queue can be turned into a priority one using client-provided optional arguments (but, unlike other features that use optional arguments, not policies). The implementation supports a limited number of priorities: 255. Values between 1 and 10 are recommended.
To declare a priority queue, use the x-max-priority
optional queue argument. This argument should be a positive integer between 1 and 255, indicating the maximum priority the queue should support. For example, using the Java client:
Channel ch = ...; Map<String, Object> args = new HashMap<String, Object>(); args.put("x-max-priority", 10); ch.queueDeclare("my-priority-queue", true, false, false, args);
Publishers then can publish prioritised messages using the priority
field of basic.properties
. Larger numbers indicate higher priority.
Priority declaration using policies is not supported by design.
The AMQP 0-9-1 spec is a bit vague about how priorities are expected to work. It says that all queues MUST support at least 2 priorities, and MAY support up to 10. It does not define how messages without a priority property are treated.
In contrast to the AMQP 0-9-1 spec, RabbitMQ queues by default do not support priorities. When creating priority queues, a maximum priority can be chosen as developer sees fit. When choosing the value, a couple of things must be taken into account.
There is some in-memory and on-disk cost per priority level per queue. There is also an additional CPU cost, especially when consuming, so you may not wish to create huge numbers of levels.
The message priority
field is defined as an unsigned byte, so in practice priorities should be between 0 and 255.
Messages without a priority
property are treated as if their priority were 0. Messages with a priority which is higher than the queue's maximum are treated as if they were published with the maximum priority.
If priority queues are desired, we recommend using between 1 and 10. Currently using more priorities will consume more CPU resources by using more Erlang processes. Runtime scheduling would also be affected.
It's important to understand how consumers work when working with priority queues. By default, consumers may be sent a large number of messages before they acknowledge any, limited only by network backpressure.
So if such a hungry consumer connects to an empty queue to which messages are subsequently published, the messages may not spend any time at all waiting in the queue. In this case the priority queue will not get any opportunity to prioritise them.
In most cases you will want to use the basic.qos
method in manual acknowledgement mode on your consumers, to limit the number of messages that can be out for delivery at any time and thus allow messages to be prioritised.
In general priority queues have all the features of standard RabbitMQ queues: they support persistence, paging, mirroring, and so on. There are a couple of interactions that developers should be aware of.
Messages which should expire will still only expire from the head of the queue. This means that unlike with normal queues, even per-queue TTL can lead to expired lower-priority messages getting stuck behind non-expired higher priority ones. These messages will never be delivered, but they will appear in queue statistics.
Queues which have a max-length set will, as usual, drop messages from the head of the queue to enforce the limit. This means that higher priority messages might be dropped to make way for lower priority ones, which might not be what you would expect.
The most convenient way to define optional arguments for a queue is via policies. Policies are the recommended way to configure TTL, queue length limits and other optional queue arguments.
However, policies cannot be used to configure priorities because policies are dynamic and can be changed after a queue has been declared. Priority queues can never change the number of priorities they support after queue declaration, so policies would not be a safe option to use.