14 AMQP Reliability: Acknowledgements and Crash Recovery
Start with the story: The dangerous AMQP mistakes are often quiet. Messages can be accepted but unrouted, queues can be durable while payloads are not, and acknowledgments can delete work before the consumer has actually finished it.
14.1 Start With the Decision
A broker can lose work when a consumer crashes after auto-ack. Compare ack modes before accepting a message.
14.2 Route Overview
This is part 2 of 2. Review AMQP Reliability: Persistence and Routing Patterns for the preceding evidence.
14.3 Learning Objectives
- Compare auto-ack and manual-ack behavior after a consumer crash.
- Route unroutable messages with alternate exchanges and wildcard bindings.
14.4 Chapter Roadmap
- Interactive Calculator: Auto-ack vs Manual-ack Crash Simulator
- Misconception Impact Summary
- Debugging Checklist
- Try It: AMQP Troubleshooting Decision Tree
- Knowledge Check
- Concept Matching: AMQP Terms and Definitions
- Label the Diagram
- Code Challenge
- Order the Steps
- Design Contract: Unroutable Messages and Wildcards
- Unroutable and Wildcard Contracts
- Summary
- What’s Next
- Key Takeaway
14.5 Misconception Impact Summary
Use the summary as a diagnostic route, while treating its frequencies and impacts as the chapter’s illustrative dataset rather than universal rates. First separate durable topology from persistent payloads: the cited 68% frequency and 15K–50K restart loss point to setting delivery_mode=2 where payload survival is required.
Next test wildcard depth. The cited 42% frequency and 20–60% missed-message impact point to # for multiple routing-key words and * for exactly one. Then inspect acknowledgment timing: the chapter associates auto-ack with 85% of its data-loss incidents and 2.5K–10K lost messages, so manual ACK belongs after successful processing.
Finally, choose protocol and execution guarantees separately. The constrained-device example associates an AMQP-first choice with roughly one-third shorter battery life than MQTT, so selection must follow measured constraints. The exactly-once row assumes every design without idempotency misses the application guarantee; duplicate commands or corrupted state are prevented by stable idempotency keys and durable deduplication records, not by a transport label alone.
14.6 Debugging Checklist
When troubleshooting AMQP message delivery issues, use this systematic checklist:
Messages Lost on Broker Restart:
First: Check queue durability: queue_declare(durable=True)
Next: Check message persistence: delivery_mode=2 in properties
Then: Check exchange durability: exchange_declare(durable=True)
After that: Verify with RabbitMQ Management: Queue shows “D” flag (durable)
Messages Not Arriving at Expected Queue:
Also inspect: Verify binding pattern matches routing key structure
Finally: Count words in routing key vs pattern (remember * = exactly 1)
Finally: Test pattern with RabbitMQ trace plugin
Finally: Check exchange exists and is correctly typed (topic vs direct vs fanout)
Messages Processed but Lost:
Finally: Check auto_ack setting (should be False for reliability)
Finally: Verify ACK sent after successful processing, not before
Finally: Check exception handling includes basic_nack with requeue
Finally: Monitor dead letter queue for rejected messages
Duplicate Message Execution:
Finally: Verify idempotency key in message_id property
Finally: Check deduplication storage (Redis/database) for executed IDs
Finally: Ensure deduplication check happens before execution
Finally: Test with simulated network glitches
14.7 Knowledge Check
14.8 Design Contract: Unroutable Messages and Wildcards
AMQP pitfall prevention is not complete until routing misses become visible instead of silent. The deeper treatment now lives in AMQP Unroutable Message and Wildcard Contracts, covering publisher confirms versus basic.return, mandatory publishes, alternate exchanges, topic wildcard word boundaries, and routing tests that catch silent drops before release.
14.9 Unroutable and Wildcard Contracts
Make a Missing Route Loud
Picture a packing line sending a quality alert that no worker ever receives. Advanced Message Queuing Protocol, or AMQP, is a protocol: a shared set of rules for moving messages. A broker is the service that accepts and routes them. Telemetry means readings and status sent from equipment for remote use.
Message Queuing Telemetry Transport, or MQTT, is another publish-and-subscribe protocol, but its wildcard marks do not mean the same thing as AMQP marks. Write the exact AMQP routing key, each binding, expected queues, no-match action, reply path, retry rule, final user, and owner.
Test one key that should reach many queues, one that should reach one, and one that should reach none. Add an extra word, remove a word, restart the broker, fill the catch-all queue, and repeat a message. Check queue contents and the user result. A broker confirm proves acceptance at one boundary, not a useful route.
Keep urgent line action local if the message route is missing. The wider path can report and coordinate, but silent loss must never look like success.
This opening does not choose every queue policy. Practitioner configures returns and alternate routes. Under the Hood examines binding words, wildcard limits, storage, confirms, replies, duplicates, and the evidence that catches a silent drop.
Start with the story: A publisher confirm can still hide a routing failure. The broker may accept a message, find no matching queue, and drop it unless mandatory returns, alternate exchanges, and wildcard tests make that failure visible.
14.9.1 Learning Objectives
After this page, you should be able to:
- Explain why a publisher confirm does not prove that a message reached a queue.
- Detect unroutable publishes with
mandatory=true,basic.return, and alternate exchanges. - Size a catch-all alternate-exchange queue for a realistic misrouting incident.
- Distinguish AMQP topic
*and#word matching from shell glob and MQTT wildcard behavior. - Build positive, negative, and boundary routing tests that prevent silent AMQP drops.
14.9.2 Why This Follows AMQP Implementation Pitfalls
AMQP Implementation Pitfalls reviews the major failure modes: durability gaps, unsafe acknowledgments, wildcard mistakes, protocol-selection errors, and missing idempotency. This page tightens one operational contract inside those pitfalls: a publish can be accepted by the broker and still reach no queue unless unroutable handling and routing-pattern tests are deliberate.
Use it when producers rely on publisher confirms, when a topic hierarchy has variable depth, when AMQP routing is being migrated from MQTT topics, or when a production runbook needs proof that bad bindings become alerts rather than missing telemetry.
14.9.3 Overview: The Dangerous Failures Are the Silent Ones
Many AMQP surprises are not crashes — they are messages that vanish with no error at all. Two common sources of "the broker is eating my messages" incidents are a message that reaches no queue and a topic binding pattern that does not match the routing key the developer assumed it would. In both cases the publish can appear successful while data never becomes available to a consumer.
A confirm and a routing verdict answer different questions. The figure below follows one AMQP 0-9-1 publish through independent binding evaluation and then shows what becomes observable when the final route count is zero.
Inspect Figure 14.1 to distinguish publisher acceptance from the later routing verdict that decides whether any queue receives a copy.
Trace Figure 14.1 through binding evaluation: zero matches require return or alternate-exchange policy, one match creates one queue copy, and several distinct matches create several copies. The confirm branch remains separate. This is the diagnostic model for silent wildcard failures developed in the chapter.
Test one key that should match several queues, one that should match exactly one, and one that should match none. For each case, record the expected queue set, alternate or return outcome, and the separate confirm result. A clean confirm without routing evidence is not proof that a consumer can receive the message.
The cure is to know exactly when AMQP discards a message quietly, and to turn those quiet discards into visible signals you can alert on. A durable queue protects the queue definition; a persistent message protects the payload; a publisher confirm says the broker accepted responsibility for the publish at its configured boundary; a consumer ACK says downstream delivery processing completed; an idempotency key makes a redelivery safe to run twice.
For example, suppose a packaging line publishes 2,400 quality alerts per hour with routing keys such as sensor.floor1.temperature.critical. If the analytics queue is bound to sensor.*, every four-word alert misses the queue even though the producer receives a confirm. At 2,400 alerts/hour, that is 19,200 missing records across one shift. With no alternate exchange, mandatory=true returns each finally unroutable publish. With a catch-all alternate exchange, the broker extends the routing chain and captures the records instead; a message successfully routed by that alternate counts as routed for the mandatory flag.
That is also why a useful review asks "which guarantee detects this failure?" for every critical path. Restart loss needs durable plus persistent storage; crash loss needs manual ACK after the side effect; duplicate execution needs an idempotency key; routing loss needs a matching binding plus return or alternate-exchange handling. If the answer is only "publisher confirms are on", the design is still missing part of the failure story.
14.9.4 Practitioner: An Unroutable Message Is Dropped by Default
When an exchange receives a message that matches no binding, its default behavior is to discard it silently. There are three ways to change that, and one dangerous misconception:
| Technique | What it does |
|---|---|
mandatory flag on publish | The broker returns the unroutable message to the publisher as a basic.return (reply code 312, NO_ROUTE) so the app can react. |
alternate-exchange on the exchange | Any message the exchange cannot route is sent to a named fallback exchange, usually feeding a catch-all queue for inspection. |
| Both together | The alternate exchange extends the routing chain. If it routes the message, no mandatory return occurs; if the final chain still reaches no queue and mandatory=true, the broker sends basic.return. |
The misconception that bites hardest: a publisher confirm does not mean "routed to a queue". The broker confirms an unroutable message as successfully handled — it did its job, there was just nowhere to send it. To detect unroutable messages you must combine confirms with the mandatory flag (or an alternate exchange). Confirms alone will happily ack data straight into the void.
A practical production check uses two intentionally bad routes before launch. First publish with mandatory=true and no alternate exchange; the publisher should receive basic.return with NO_ROUTE. Then publish through the production exchange with its catch-all alternate configured; the catch-all queue should receive the message and the publisher should not receive a mandatory return because the routing chain found a queue. If the alternate chain also reaches no queue, mandatory=true makes that final zero-route result visible as basic.return. Publisher confirm remains a separate acceptance signal; for a finally unroutable mandatory publish, the return is delivered before the confirm acknowledgement.
Size the catch-all queue as an incident buffer, not as the normal data path. If the plant publishes 40 messages/s and a bad release misroutes 10% for 15 minutes, the alternate queue needs room for 40 x 0.10 x 900 = 3,600 messages plus margin. Alert on any non-zero return rate for critical streams, and alert separately when alternate-exchange depth grows faster than the operator can drain it. That turns a routing typo into a visible rollback trigger instead of a missing-data investigation tomorrow.
14.9.5 Under the Hood: Topic Wildcards Are Word-Matching, Not Glob
Topic routing keys are dot-separated words, and the two wildcards mean precise, different things: * matches exactly one word; # matches zero or more words. The most common bug is expecting * to span multiple levels the way a shell glob would.
| Binding pattern | sensor.floor1.temp | sensor.floor1.temp.critical | sensor |
|---|---|---|---|
sensor.* | no (needs exactly 2 words) | no | no |
sensor.*.temp | yes | no | no |
sensor.# | yes | yes | yes |
Note that sensor.* matches only keys of the form sensor.<one-word> — so it matches sensor.floor1 but not sensor.floor1.temp (too many words) and not sensor (too few). If you want "everything under sensor" you need sensor.#. This also differs from MQTT, whose wildcards are + (one level) and # (rest of the tree, and only as the final token). Same idea, different characters and different edge behavior — a frequent source of migration bugs.
The exchange evaluates each binding independently. A single publish can match zero queues, one queue, or several queues; it is not a first-match router. With bindings sensor.#, sensor.*.temp, and sensor.floor1.#, the key sensor.floor1.temp routes to all three queues. The key sensor.floor1.temp.critical routes to sensor.# and sensor.floor1.#, but not sensor.*.temp, because that pattern has exactly three words and the routing key has four.
This is why routing tests should include negative and boundary cases. For a binding intended to capture "all temperature under any floor", test sensor.floor1.temp, sensor.floor1.room7.temp, sensor.temp, and sensor.floor1.temp.critical. If only the first passes, the binding is fixed-depth; if all relevant depths pass and unrelated keys fail, it is a safe hierarchy binding. Keep these tests next to publisher-confirm tests so the team does not confuse "broker accepted the message" with "a consumer can receive the message".
14.10 Summary
This chapter covered critical AMQP implementation misconceptions that cause production failures:
First: Persistence requires both durable queues AND delivery_mode=2 - 68% of deployments get this wrong, losing messages on restart
Next: Wildcard * matches exactly one word, # matches zero or more - 42% of systems have incorrect patterns missing messages
Then: Auto-ack loses messages on any failure regardless of processing speed - Responsible for 85% of data loss incidents
After that: AMQP vs MQTT: Choose based on constraints, not reputation - AMQP has 4-10x higher per-message protocol overhead than MQTT (8-20 bytes vs 2 bytes fixed header)
Also inspect: Exactly-once requires application-level idempotency - No system achieves it without explicit deduplication
14.11 What’s Next
-
AMQP Routing Patterns and Exercises Focus: Wildcard patterns, exchange types, binding design Why read it: Apply correct
*vs#usage and build routing topologies that avoid the pattern-matching pitfalls covered here. -
AMQP Production Operations Focus: Publisher confirms, connection pooling, retry logic Why read it: Implement the persistence and acknowledgment configurations that prevent the five misconceptions in production code.
-
AMQP Fundamentals Focus: Exchange types, queue bindings, protocol model Why read it: Reinforce the conceptual foundation behind why durable queues and persistent messages are independent settings.
-
AMQP Architecture and Frames Focus: Protocol frames, channel model, message properties Why read it: Understand the wire-level mechanism by which
delivery_mode=2causes disk writes and how publisher confirms work at the frame level. -
MQTT Protocol Focus: MQTT QoS levels, lightweight pub/sub Why read it: Compare MQTT delivery guarantees directly with AMQP acknowledgment modes - critical for the protocol selection decision in Misconception 4.
-
AMQP Implementations Overview Focus: Full implementation guide, labs Why read it: Return to the parent chapter for the complete AMQP implementation guide connecting all misconception fixes into working code.
14.12 Key Takeaway
Most AMQP implementation failures come from treating broker features as defaults instead of decisions. Check durability, prefetch, acknowledgements, connection recovery, and dead-letter routing explicitly for each deployment.
14.13 Continue Your Route
This final part closes the route from Interactive Calculator: Auto-ack vs Manual-ack Crash Simulator through Key Takeaway. Return to AMQP Reliability: Persistence and Routing Patterns or continue from the amqp module index.
