Priority Queues
IntermediateDeclare x-max-priority on a queue to enable priority levels (0–255); higher-priority messages are delivered first, allowing urgent tasks to skip ahead of normal work.
Overview
RabbitMQ priority queues extend classic queues with a binary heap per priority level. When you declare x-max-priority on a queue, the broker allocates internal sub-queues and delivers higher-priority messages first, regardless of arrival order. This solves use cases like urgent order cancellations jumping ahead of regular order updates, or premium-tier API requests being processed before free-tier ones. Priority only matters when the queue has a backlog — if consumers keep up, all messages are delivered as they arrive anyway. Key constraints: priority works only with classic queues (not quorum queues), and setting x-max-priority too high wastes memory because an empty sub-queue still consumes resources.
Declaring a priority queue
Add x-max-priority to the queue declaration. Publishers set the priority property per message (0 = lowest, x-max-priority = highest). Spring AMQP supports this via QueueBuilder and MessageProperties.
@Configuration
public class PriorityQueueConfig {
// Declare priority queue with max 10 priority levels (0–10)
// Keep x-max-priority small (≤10) — each level needs its own internal queue
@Bean
public Queue orderPriorityQueue() {
return QueueBuilder.durable("orders.priority")
.withArgument("x-max-priority", 10)
.build();
}
}
// Publisher: set priority per message
@Service
public class OrderPublisher {
@Autowired
private RabbitTemplate rabbitTemplate;
public void publish(OrderEvent event, int priority) {
rabbitTemplate.convertAndSend(
"orders.exchange", "order.priority", event,
message -> {
message.getMessageProperties().setPriority(priority);
return message;
}
);
}
public void publishUrgent(OrderEvent event) {
publish(event, 10); // highest priority — jumps the queue
}
public void publishNormal(OrderEvent event) {
publish(event, 5); // medium
}
public void publishBulk(OrderEvent event) {
publish(event, 1); // lowest priority
}
}Priority queue behaviour and consumer interaction
Priority is only effective when there is a backlog. Consumer prefetch count affects how messages are batched — a large prefetch can cause low-priority messages to be fetched even when high-priority ones arrive.
// Priority only helps when the queue has a backlog.
// If consumers are faster than producers, all messages are delivered FIFO.
// Set prefetch=1 per consumer to ensure high-priority messages are not
// buffered behind lower-priority ones at the consumer.
@Bean
public SimpleRabbitListenerContainerFactory priorityListenerFactory(
ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setPrefetchCount(1); // critical: don't pre-fetch multiple priorities
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
}
@RabbitListener(
queues = "orders.priority",
containerFactory = "priorityListenerFactory"
)
public void handle(OrderEvent event,
@Header(AmqpHeaders.PRIORITY) Integer priority,
Acknowledgment ack) {
log.info("Processing priority {} order {}", priority, event.getOrderId());
processOrder(event);
ack.acknowledge();
}Priority queues vs routing alternatives
For most use cases, separate queues per tier is simpler and more reliable than x-max-priority. Priority queues are limited to classic queues and have memory overhead per level.
// ALTERNATIVE: separate queues per priority tier
// Exchange routes by routing key; each queue has dedicated consumers
@Bean
public TopicExchange ordersExchange() {
return new TopicExchange("orders.exchange");
}
@Bean
public Queue urgentQueue() {
return QueueBuilder.durable("orders.urgent").build();
}
@Bean
public Queue normalQueue() {
return QueueBuilder.durable("orders.normal").build();
}
@Bean
public Binding urgentBinding() {
return BindingBuilder.bind(urgentQueue())
.to(ordersExchange())
.with("order.priority.urgent");
}
// Publisher routes by routing key instead of priority property
rabbitTemplate.convertAndSend("orders.exchange",
isPremium ? "order.priority.urgent" : "order.priority.normal", event);
// When to use x-max-priority vs separate queues:
// x-max-priority: single queue, dynamic reordering, up to 10 levels
// Separate queues: clearer ops, dedicated consumers per tier, no memory overheadKey Points to Remember
- 1x-max-priority works only on classic queues — quorum queues do not support priority.
- 2Keep x-max-priority ≤ 10; each priority level allocates an internal sub-queue even when empty.
- 3Priority only matters under backlog — if consumers keep up, messages are still delivered FIFO.
- 4Set consumer prefetch=1 when using priority queues to prevent high-priority messages being blocked behind pre-fetched low-priority ones.
- 5For more than ~3 priority tiers, separate queues per tier with dedicated consumers is more predictable.
- 6Monitor queue depth per-queue (not per-priority); there is no per-priority depth metric in RabbitMQ management.
Interview Questions
Sign in to ask AriaHow do you declare a priority queue in RabbitMQ and what is the maximum useful priority level?
Why does consumer prefetch size affect priority queue effectiveness?
When would you use separate queues per tier instead of x-max-priority?
Priority queues are not available on quorum queues — what alternative would you use?
Explain a scenario where priority queues could cause starvation of low-priority messages.
Ask Aria about Priority Queues
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.