Durability, persistence and publisher confirms

RabbitMQ · Practical · 14 min

Without confirms a publisher can't know whether the broker actually stored a message; this is where silent data loss happens.

Three separate settings decide whether a message survives problems:

  • Durable queue (durable=True): the queue definition survives a broker restart. Quorum queues and streams are always durable.
  • Persistent message (delivery_mode=2, pika.DeliveryMode.Persistent): the message is written to disk. For classic queues, a persistent message in a durable queue survives restarts; a transient message does not. Quorum queues and streams store all messages durably.
  • Publisher confirms: the broker acknowledges each published message after it has been routed and safely stored (written to disk, and replicated for quorum queues). Without confirms, a message lost in a network failure or broker crash just disappears.

Enable confirms on a channel with confirm_delivery() in pika; each basic_publish then waits for the confirm, and raises UnroutableError (with mandatory=True) or NackError on failure. Waiting per message is slow; high-throughput publishers keep many messages in flight and handle confirms asynchronously, or publish in batches and wait for the batch.

Even with confirms, the publisher needs a strategy for failures: retry (and accept possible duplicates), buffer locally, or fail the request. Combine confirms with consumer acks for end-to-end at-least-once delivery.

Example

import pika
from pika.exceptions import UnroutableError, NackError

ch = pika.BlockingConnection(pika.ConnectionParameters("localhost")).channel()
ch.queue_declare(queue="orders", durable=True)      # survives restarts
ch.confirm_delivery()                               # enable publisher confirms

props = pika.BasicProperties(delivery_mode=pika.DeliveryMode.Persistent,
                             content_type="application/json")
try:
    ch.basic_publish("", "orders", b'{"id": 1}', properties=props, mandatory=True)
    print("confirmed by broker")                    # stored safely
    ch.basic_publish("", "no-such-queue", b"x", properties=props, mandatory=True)
except UnroutableError:
    print("returned: no queue matched")             # returned: no queue matched
except NackError:
    print("broker could not store it; retry later")

Remember

  • Durable queue + persistent message survive a broker restart
  • Publisher confirms tell you the broker stored the message
  • mandatory=True returns unroutable messages instead of dropping them

Watch out for

  • Assuming durable=True on the queue makes messages persistent; classic queue messages also need delivery_mode=2.

Check yourself

  1. Why use publisher confirms if the queue is durable and messages are persistent?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.rabbitmq.com/docs/confirms#publisher-confirms