100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Messaging

Message Acknowledgments

Understand how RabbitMQ acknowledgments, nacks, and rejections protect against message loss and prevent poison-message loops.

Messaging PatternsIntermediate9 min readJul 10, 2026
Analogies

Why Acknowledgments Exist

A message acknowledgment (ack) is the signal a consumer sends back to RabbitMQ confirming it has fully processed a message and the broker can safely delete it from the queue. Without acknowledgments, RabbitMQ would have to assume delivery equals success, which is dangerous — a consumer could crash mid-processing, losing the message forever with no way to recover it. By default, RabbitMQ consumers use manual acknowledgment mode, meaning the broker holds a message as 'unacked' from the moment it is delivered until the consumer explicitly calls basic_ack, and will redeliver it to another consumer if the original one disconnects first.

🏏

Cricket analogy: It is like a fielder only being credited with a clean catch once the umpire's soft-signal review confirms the ball didn't touch the ground, rather than the broadcast assuming a catch is clean the instant the fielder claims it.

Manual Ack, Nack, and Reject

Beyond the simple basic_ack, RabbitMQ supports basic_nack and basic_reject for cases where processing fails. basic_nack (which can negatively acknowledge one message or, with multiple=True, a whole batch) and basic_reject both let the consumer signal failure, and each accepts a requeue flag: requeue=True puts the message back at the front of the queue for redelivery, while requeue=False either discards it or, if a dead-letter exchange is configured, routes it there for inspection or retry with backoff. Choosing requeue=True carelessly on a message that always fails processing creates a poison-message loop, where the same message is redelivered and rejected forever, burning CPU without making progress.

🏏

Cricket analogy: It is like a third umpire either confirming a run-out (ack), sending it back for another camera angle (nack with requeue), or ruling it unreviewable and moving on (reject without requeue) — but repeatedly requesting the same inconclusive replay forever would just stall the match without ever reaching a decision.

python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(host="localhost"))
channel = connection.channel()
channel.queue_declare(queue="image_resize", durable=True)
channel.basic_qos(prefetch_count=1)

def callback(ch, method, properties, body):
    try:
        resize_image(body)
        ch.basic_ack(delivery_tag=method.delivery_tag)
    except TransientError:
        # Temporary failure: retry later
        ch.basic_nack(delivery_tag=method.delivery_tag, requeue=True)
    except CorruptFileError:
        # Permanent failure: don't requeue, route to DLX instead
        ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)

channel.basic_consume(queue="image_resize", on_message_callback=callback)
channel.start_consuming()

Configure a dead-letter exchange (x-dead-letter-exchange) on the queue so that messages rejected with requeue=False land in a separate queue for inspection, alerting, or manual replay instead of vanishing silently.

Auto-Ack: Convenient but Risky

Setting auto_ack=True (or the deprecated no_ack=True) tells RabbitMQ to consider a message acknowledged the instant it is delivered over the network, before the consumer has done any work. This trades safety for a small throughput gain and the removal of prefetch-based flow control, since the broker no longer needs to track unacked messages per consumer. Auto-ack is reasonable for purely disposable, low-value telemetry where an occasional dropped message is acceptable, but it is the wrong choice for any task — order processing, payment events, job execution — where losing a message silently would cause real damage.

🏏

Cricket analogy: It is like a scorer marking a run as confirmed the instant the batters start running, before the fielder's throw and stumping attempt are even resolved — fine for a rough live text commentary feed, but unacceptable for the official scorecard that decides the match result.

Auto-ack silently discards RabbitMQ's core reliability guarantee: if the consumer process crashes after delivery but before finishing its work, the message is gone permanently with no redelivery. Never use auto-ack for anything you cannot afford to lose.

  • An acknowledgment (ack) tells RabbitMQ a message was fully processed and can be safely removed from the queue.
  • Manual acknowledgment mode holds a message as 'unacked' until basic_ack is called, and redelivers it if the consumer disconnects first.
  • basic_nack and basic_reject signal processing failure; the requeue flag decides whether the message is retried or discarded/dead-lettered.
  • Careless requeue=True on permanently-failing messages creates a poison-message loop that burns CPU without progress.
  • Dead-letter exchanges (x-dead-letter-exchange) capture rejected, non-requeued messages for inspection instead of silently dropping them.
  • Auto-ack trades reliability for a small throughput gain and should be reserved for genuinely disposable, low-value data.
  • prefetch-based fair dispatch only works with manual acknowledgment, since it depends on knowing which messages are still unacked.

Practice what you learned

Was this page helpful?

Topics covered

#Messaging#RabbitMQStudyNotes#Database#MessageAcknowledgments#Message#Acknowledgments#Exist#Manual#StudyNotes#SkillVeris