10 AMQP Delivery: Sizing and Reliability Contracts
More
Depth: Practitioner
Progress saves as you read. Mark sections complete as you go; your progress appears in the sidebar.
Start with the story: An AMQP message is a parcel with a label, a body, and a delivery receipt path. The chapter is about choosing when that parcel may be dropped, retried, acknowledged, or parked for investigation.
10.1 Start With the Decision
This section: Start With the Decision — Five hundred machines can turn a safe message rule into a queue bottleneck.
Five hundred machines can turn a safe message rule into a queue bottleneck. Size, rate, prefetch, and failure flow must be counted.
10.2 Route Overview
This section: Route Overview — This is part 2 of 2.
This is part 2 of 2. Review AMQP Delivery: Guarantees and Acknowledgements for the preceding evidence.
10.3 Learning Objectives
This section: Learning Objectives
- Calculate smart-factory message volume and throughput.
- Verify an AMQP reliability chain with explicit contracts.
10.4 Chapter Roadmap
This section: Chapter Roadmap
- Worked Example: Smart Factory Message Sizing
- Putting Numbers to It
- Checkpoint: Sizing the Reliability Chain
- Knowledge Check
- Quiz: Match Concepts to Definitions
- Label the Diagram
- Code Challenge
- Order the Steps
- Design Contract: Delivery Reliability Chain
- AMQP Delivery Reliability Chain Contracts
- Summary
- What’s Next
- Key Takeaway
10.5 Worked Example: Smart Factory Message Sizing
This section: Worked Example: Smart Factory Message Sizing — Now combine structure, guarantees, acknowledgments, and DLQ handling.
Now combine structure, guarantees, acknowledgments, and DLQ handling. Pay for reliability where the consequence justifies it.
Scenario: A pharmaceutical manufacturing plant monitors 500 machines via AMQP. Each machine publishes three types of messages with different delivery requirements:
| Message Type | Frequency | Payload | Delivery Need |
|---|---|---|---|
| Temperature telemetry | Every 5 seconds | 120 bytes JSON | Occasional loss OK |
| Quality alert | On threshold breach (~10/hour/machine) | 350 bytes JSON | Must not be lost |
| Batch completion event | ~2 per hour per machine | 800 bytes JSON | At-least-once delivery with an idempotent audit write |
Step 1: Calculate message rates and bandwidth
- Telemetry: 500 machines x 1 msg/5s = 100 msg/s
- Quality alerts: 500 x 10/hr = 5,000/hr = 1.39 msg/s
- Batch events: 500 x 2/hr = 1,000/hr = 0.28 msg/s
- Total: ~102 msg/s
Step 2: Calculate per-message AMQP overhead
For this illustrative AMQP 0-9-1 sizing model, assume these frame sizes (actual sizes depend on field values and properties):
- Method-frame envelope: 8 bytes
- Method-frame content (basic.publish): ~40 bytes (exchange name, routing key)
- Content-header frame: ~60 bytes (properties: delivery_mode, content_type, timestamp, message_id, correlation_id)
- Content-body envelope: 8 bytes + payload
Illustrative overhead per message: 8 + 40 + 60 + 8 = ~116 bytes
Step 3: Choose delivery mode for each type
| Type | QoS | Overhead per msg | Rationale |
|---|---|---|---|
| Telemetry | At-most-once | 120 + 116 = 236 B | Next reading in 5s replaces any loss |
| Quality alert | At-least-once | 350 + 116 = 466 B + ACK (40 B) | Must arrive; dedup via message_id |
| Batch event | Transactional publish + idempotent audit write | 800 + 116 = 916 B + assumed 200 B transaction cost | Audit write must reject duplicate event IDs |
Step 4: Aggregate bandwidth
- Telemetry: 100 msg/s x 236 B = 23,600 B/s = 189 Kbps
- Alerts: 1.39 msg/s x 506 B = 703 B/s = 5.6 Kbps
- Batch: 0.28 msg/s x 1,116 B = 312 B/s = 2.5 Kbps
- Total: ~197 Kbps (well within a 1 Mbps LAN connection)
AMQP protocol overhead per message consists of multiple frame components:
Message efficiency for different payload sizes:
| Payload | Total Size | Efficiency |
|---|---|---|
| 10 B | 126 B | 7.9% (poor) |
| 120 B | 236 B | 50.8% (moderate) |
| 800 B | 916 B | 87.3% (good) |
For telemetry with 120-byte payloads, nearly half the bandwidth is protocol overhead. Batching 10 readings into one 1,200-byte message improves efficiency from 51% to 91%, saving per 10 readings (44% reduction).
10.5.1 Interactive Calculator: AMQP Message Sizing
10.5.2 Interactive Calculator: AMQP Bandwidth Requirements
Step 5: Broker memory for persistent sessions
Quality alerts and batch events use persistent delivery (delivery_mode=2):
- Persistent messages per second: 1.39 + 0.28 = 1.67 msg/s
- Assumed average persistent message size: ~810 bytes (weighted on-wire size: (1.39 x 506 + 0.28 x 1116) / 1.67 ≈ 608 B; allow ~810 B with the example’s broker-framing estimate).
- If a consumer goes offline for 10 minutes: 1.67 x 600 = 1,002 messages ≈ ~810 kB queued
- With 5 consumers, worst case: ~4 MB broker memory for queued messages
Conclusion: The telemetry (about 98% of messages) uses fire-and-forget, keeping broker load minimal. Only alerts and batch events use persistent delivery in this scenario. Adding the assumed 200-byte transaction cost to every message would raise this model’s bandwidth from ~197 to ~360 Kbps (about 1.8×); transactions alone would not provide exactly-once business processing.
This section:
Checkpoint: Sizing the Reliability Chain
You now know:
- The factory example produces about 102 messages per second from 500 machines.
- Telemetry is 98% of traffic, so at-most-once keeps the total near 197 Kbps.
- Persistent alerts and batch events are only 2% of messages, but they drive offline broker memory.
10.6 Knowledge Check
This section: Knowledge Check — Test your understanding of message structure and delivery guarantees.
Test your understanding of message structure and delivery guarantees.
AMQP dead-letter routing narrated tour
Play silently with captions on provisional storyboard timing; narration audio is pending. Production pacing is not protocol time. Choose Reduced motion for a complete still at each beat.
Play the tour to open the workbench. Pause, replay a beat, or read the full transcript below. Some situations cannot be shown by this teaching model; those beats keep the existing frame and provide captions only.
Full transcript — AMQP dead-letter routing (8 beats)
B1 — Unreadable payload
You are the engineer keeping a factory's sensor messages moving. A decoder cannot read one message's payload, the data it carries. If that bad message keeps returning to the main queue, it can block good traffic. How do you move it aside while keeping the details needed to repair the fault?
Model caption: An unreadable sensor payload can block useful work if it keeps returning to the main queue.
B2 — Dead-letter route
Dead-lettering gives failed work another route. A queue configured with a dead-letter exchange republishes the message to that exchange. An exchange routes messages onward using a routing key. For your failed sensor message, that route separates the failure from the main flow of work.
Model caption: A configured source queue republishes failed work to a dead-letter exchange.
B3 — Failure triggers
Rejection without returning the message to the source queue can trigger dead-lettering. So can expiry of its time to live, meaning its allowed lifetime. Queue overflow is another trigger: exceeding a length limit drops the oldest message by default.
Model caption: Rejection without requeue, lifetime expiry, or length overflow can trigger the chapter's dead-letter route. Overflow drops the oldest message by default.
B4 — Routing and evidence
The dead-letter route uses a configured replacement routing key when one is set. Otherwise, it uses the original routing key. The broker adds failure details in a header called x-death. Those details include the reason, source queue and count. The count helps a retry policy decide when to stop.
Model caption: A replacement routing key is used when configured; otherwise the original key is used. The x-death header carries failure context for the retry policy.
B5 — Retry delay example
Take the chapter's decoder example. The decoder rejects the unreadable payload without requesting a return to the source queue. The dead-letter exchange routes it to a retry queue with a thirty-second lifetime. After thirty seconds, that queue dead-letters the message back to the main exchange for another attempt.
Model caption: Chapter example: rejected payload → retry queue; wait thirty seconds → main exchange for another attempt.
B6 — Parking after failures
Suppose the message reaches three failed attempts. The handler can send it to a parking queue for investigation. The original body and headers stay with it. The failure reason and source queue are preserved too. Your bad sensor message is set aside with the context needed for repair.
Model caption: After three failed attempts, the handler can park the message. Preserve its body and headers, plus the failure reason and source queue, for investigation.
B7 — Routing is not repair
The misconception is that dead-lettering repairs the failed message automatically. Moving an unreadable payload to another queue does not make the decoder able to read it. In the example, the retry policy uses the failure history to stop after three failed attempts and send the message to parking.
Model caption: Dead-lettering moves failed work. The example's retry policy stops after three failures; repair still requires investigation.
B8 — Failure route takeaway
Give failed work a route, a retry limit and a place to stop with its failure details intact.
Model caption: Give failed work a route, a retry limit and a place to stop with its failure details intact.
10.7 Design Contract: Delivery Reliability Chain
This section: Design Contract: Delivery Reliability Chain — Reliable AMQP delivery is a chain, not one setting.
Reliable AMQP delivery is a chain, not one setting. The deeper treatment now lives in AMQP Delivery Reliability Chain Contracts, covering publisher confirms, durable queues, persistent messages, manual acknowledgments, idempotent redelivery, and DLX retry/parking evidence paths.
10.8 AMQP Delivery Reliability Chain Contracts
This section: AMQP Delivery Reliability Chain Contracts — Start with the story: Reliability in AMQP is not one magic checkbox.
Start with the story: Reliability in AMQP is not one magic checkbox. It is a chain of receipts: the producer needs a broker confirm, the broker needs durable storage, the message needs persistence, and the consumer must acknowledge only after the real work is done.
10.8.1 Learning Objectives
Prove Every Link in One Alarm Chain
Picture a site unit sending a valve alarm to an incident worker. The message reaches a queue, the worker writes the incident, and then the worker crashes before it says the job is done. The next worker may see the same alarm, so the team must prevent a second incident without losing the first.
Trace one alarm from local copy to accepted store, waiting queue, worker, final record, and done signal. Name what each signal proves and what it does not. Keep one alarm id through every link so a resend or redelivery can be joined to the same physical event.
Test a failed send, a store restart, a message held only in memory, a worker crash before and after the write, a rejected item, and a full retry path. Check both loss and duplicate effects. One durable setting cannot protect a different gap in the chain.
Keep any urgent safe valve action local when delivery is late. The chain can notify and retain evidence, but it must not be the sole route to stop immediate harm.
This opening does not promise exactly-once physical action. Practitioner maps each loss window and owner. Under the Hood examines confirms, durable definitions, stored bodies, worker replies, repeated delivery, dead-letter paths, and safe replay.
After this page, you should be able to:
- Explain why publisher confirms, queue durability, message persistence, and consumer acknowledgments protect different loss windows.
- Diagnose which reliability link is missing from an AMQP delivery path.
- Explain why at-least-once delivery requires idempotent consumers.
- Identify the exact broker triggers that dead-letter a message.
- Design a DLX retry and parking flow that preserves investigation evidence.
10.8.2 Why This Follows AMQP Message Delivery
AMQP Message Delivery teaches message structure, delivery modes, publisher confirms, consumer acknowledgments, prefetch, dead-letter queues, and delivery sizing. This page tightens the contract that connects those pieces: no single flag makes delivery reliable, and each acknowledgment only means something inside its scope.
Use it when a deployment needs a zero-loss audit, when a durable queue still loses messages after restart, when repeated deliveries must be made safe with idempotency, or when a DLQ runbook needs to distinguish retryable failures from messages that should move to parking.
10.8.3 Overview: “Reliable” Is a Chain, Not a Switch
A message survives from producer to processed only if every link in a chain holds. There is no single “reliable” flag. At-least-once delivery end to end needs four independent mechanisms lined up:
- Publisher confirms so the producer knows the broker actually took the message.
- A durable queue so the queue definition survives a broker restart.
- A persistent message (
delivery-mode = 2) so the message body is written to disk, not just held in RAM. - Consumer acknowledgements so the broker only removes a message after it has been processed, not merely delivered.
Break any one and you open a silent loss window: no confirm means the producer never learns a publish was dropped; a non-durable queue vanishes on restart; a transient message in a durable queue is still lost on restart; auto-ack deletes a message the instant it is sent, before the consumer has done anything with it.
Concrete chain example: a gateway sends a valve-state alarm and keeps its local copy until the broker sends a publisher confirm. If the broker crashes before the confirm, the gateway resends from local storage. If the broker confirms and then restarts, the durable queue and persistent message are what make the alarm still appear after recovery. If the consumer receives the alarm, writes it to an incident table, and crashes before basic.ack, the broker requeues the unacknowledged delivery on channel close. That is why the downstream incident write needs an alarm id: the next consumer may see the same delivery again, and the database should treat it as the same alarm, not a second incident.
The practical audit question is therefore always, “where can the message be acknowledged but not yet recoverable?” Publisher confirms answer the producer side, persistence answers the broker restart side, and manual acknowledgements answer the consumer side. Treating those as one chain keeps operators from over-trusting a single durable setting.
10.8.4 Practitioner: What Each Link Protects Against
| Mechanism | Protects against | If you omit it |
|---|---|---|
Publisher confirm (confirm.select) | Broker rejected, unroutable, or crashed mid-publish | Producer believes a lost message was delivered |
Durable queue (declare durable=true) | Broker restart wiping the queue definition | Queue and all its messages disappear on restart |
Persistent message (delivery-mode=2) | Broker restart wiping in-memory message bodies | Durable queue comes back empty |
Manual consumer ack (basic.ack) | Consumer crashing after delivery, before processing | Message removed on delivery; work is lost |
The two disk settings only work together: a persistent message in a transient queue is not saved, and a transient message in a durable queue is not saved either. You need both. Publisher confirms even close the fsync race — the broker only confirms a persistent message routed to a durable queue after it is on disk.
Worked example — a meter reading that must not be lost. The producer opens confirm mode, publishes with delivery-mode=2 to a durable queue, and waits for the broker’s confirm before deleting its local copy. The consumer reads, writes the reading to the database, and only then sends basic.ack. If the consumer dies between read and ack, the broker sees the channel drop, requeues the unacked message, and another consumer reprocesses it.
Now add sizing. If four consumers each use basic.qos(prefetch_count=20), as many as 80 messages can be delivered but unacknowledged at once. A worker crash with 17 unacked messages does not lose those messages; they return to the queue when the channel closes. A producer using confirms in batches of 50 should keep at least the current unconfirmed batch locally, because a connection drop after publishing message 1,237 but before its confirm leaves the producer unsure whether the broker stored it. Retrying from a message id makes the duplicate detectable.
That requeue is why at-least-once can duplicate. AMQP 0-9-1 does not give true exactly-once on its own; you reach “effectively once” by making the consumer idempotent — dedupe on the message-id or a natural key so a reprocessed message is harmless.
10.8.5 Under the Hood: When a Message Is Dead-Lettered
A queue configured with x-dead-letter-exchange re-publishes a message to that exchange on exactly three triggers — nothing else:
- the consumer rejects or nacks it with
requeue=false(a poison message it cannot process), - the message’s TTL expires (a per-message
expirationor the queue’sx-message-ttl), or - the queue overflows a length limit (
x-max-lengthorx-max-length-bytes), which by default drops the oldest message.
On dead-lettering, the broker routes the message to the dead-letter exchange using x-dead-letter-routing-key if set, otherwise the message’s original routing key, and prepends an x-death header recording the reason, the source queue, a count, and a timestamp. That count is what lets a retry loop give up after N attempts instead of cycling a poison message forever. A common design is: main queue -> DLX -> a “retry” queue with a short TTL that dead-letters back to the main exchange, plus a “parking” queue for messages whose x-death count has exceeded the limit.
For example, a decoder that cannot parse a payload should send basic.nack(requeue=false), not keep requeueing the same poison message at the head of the main queue. The DLX can route it to a retry queue with x-message-ttl=30000; after 30 seconds that retry queue dead-letters it back to the main exchange. When the message fails again, the next x-death entry or count tells the retry policy it has already been through the loop. After three failed attempts, the handler can route it to a parking queue with the original body, headers, failure reason, and source queue preserved for investigation. The DLQ is therefore an evidence path as much as a reliability path: it stops one bad message from blocking good traffic while keeping enough context to repair the producer or consumer.
Inspect Figure 10.1 to separate a bounded retry loop from the terminal evidence path for a poison message.
-
One message fails. Bex moves it off the main line.
-
The broker saves why it failed and adds one count.
-
A retry line waits, then sends the message back.
-
It fails again. The saved count reaches the limit.
-
Bex parks it with its evidence. Good work can pass.
Trace Figure 10.1 from the main queue through rejection, expiry, or overflow into the dead-letter exchange. Retryable work waits in the TTL queue and returns; excessive failures move to parking with context intact. This route turns x-death history into a retry decision instead of an infinite cycle.
10.9 Summary
This section: Summary
This chapter covered AMQP message structure and delivery guarantees:
First: Message Format: Analyzed header (durable, priority, TTL), properties (content-type, correlation-ID, message-ID), and body sections
Next: Delivery Modes: Compared at-most-once (fast, may lose), at-least-once (retried, may duplicate) and transactional publishing; an exactly-once business effect still needs application deduplication
Then: Publisher Confirms: Implemented broker acknowledgment to producers for reliable publishing
After that: Consumer Acknowledgments: Applied manual ACK/NACK with prefetch control for processing guarantees
Also inspect: Dead Letter Queues: Configured DLQ for capturing failed messages for investigation
Finally: Idempotency: Used message-ID for deduplication in at-least-once scenarios
10.10 What’s Next
This section: What’s Next
| Chapter | Focus | Why Read It |
|---|---|---|
| AMQP Frames and Reliability | SASL authentication, TLS encryption, and AMQP 1.0 frame types | Secure and inspect the protocol layer that carries the messages you configured here |
| AMQP Core Architecture | Exchanges, queues, bindings, and the producer-broker-consumer model | Reinforce how message routing decisions upstream affect the delivery guarantees you set |
| AMQP Implementations and Labs | RabbitMQ broker setup, hands-on queue and DLQ configuration | Apply publisher confirms and DLQ patterns in a running broker environment |
| MQTT QoS Levels | MQTT at-most-once, at-least-once, and exactly-once equivalents | Compare AMQP delivery semantics with the constrained-device protocol used across most IoT edge devices |
| CoAP Fundamentals and Architecture | RESTful CoAP reliability via CON/NON message types | Contrast AMQP’s broker-mediated guarantees with CoAP’s direct endpoint reliability model |
| Protocol Integration Patterns | Bridging AMQP with MQTT, CoAP, and HTTP in IoT gateways | See how the delivery guarantees studied here propagate (or break) across protocol translation boundaries |
10.11 Key Takeaway
This section: Key Takeaway — Reliable AMQP delivery depends on explicit acknowledgement and redelivery behavior.
Reliable AMQP delivery depends on explicit acknowledgement and redelivery behavior. Choose prefetch, acknowledgement timing, and dead-letter handling together so slow consumers do not turn into hidden message loss or unbounded backlog.
10.12 Continue Your Route
This section: Continue Your Route — This is the last part of this chapter.
This is the last part of this chapter. Return to AMQP Delivery: Guarantees and Acknowledgements or continue from the AMQP Module Guide.
Find help
3 reviewed answers.
Where should I start in a module?
Open the module page from the sidebar to see its chapters in order. Use the module map to return to a topic you need.
Modules and pathsReviewed
What can I try when a project does not work?
Check the symptom, then work through the diagnostic steps. Keep the error message and the smallest example that reproduces it.
When you are stuckReviewed
How do interactive examples work?
Use the interactive guide to check how examples and simulations work before changing your project.
Interactive examples guideReviewed
