7 AMQP 1.0 Credit and Settlement Contracts
Start with the story: AMQP 1.0 is what happens when the broker conversation becomes a negotiated handoff instead of a fixed RabbitMQ-style exchange-and-queue script. Before reading packet captures, picture each receiver handing out “permission slips” for how many deliveries it is ready to accept, then settling each delivery with a clear receipt.
7.1 Learning Objectives
After this page, you should be able to:
- Explain why AMQP 1.0 is not a newer wire-compatible version of AMQP 0-9-1.
- Map AMQP 0-9-1 channels, publishing, prefetch, and acknowledgments to AMQP 1.0 sessions, links, credit, transfers, and dispositions.
- Trace how receiver-granted link credit constrains AMQP 1.0 message flow.
- Choose settlement behavior for at-most-once, at-least-once, and exactly-once link guarantees.
- Debug an AMQP 1.0 stalled transfer by checking both link credit and the session window.
7.2 Why This Follows AMQP Features and Frames
AMQP Features and Frames introduces frame roles, routing patterns, reliability features, AMQP 1.0 frame types, and the frame sequence workbench. This page narrows in on the design contract that matters during migrations and packet captures: AMQP 0-9-1 exposes exchanges, queues, bindings, and broker methods on the wire, while AMQP 1.0 exposes connections, sessions, links, credit, transfers, dispositions, and settlement.
Use it when a RabbitMQ team is moving to an AMQP 1.0 broker, when a gateway uses both telemetry and command streams on one connection, or when a packet trace shows flow credit and unsettled deliveries instead of basic.qos and basic.ack.
7.3 Overview: AMQP 1.0 Is a Different Protocol from AMQP 0-9-1
It is easy to assume AMQP 1.0 is just a newer AMQP 0-9-1, but they are genuinely different wire protocols that happen to share a name. AMQP 0-9-1 (what RabbitMQ speaks by default) bakes the broker model – exchanges, queues, bindings – into the protocol. AMQP 1.0 (the OASIS/ISO standard) deliberately does not: it standardises only the symmetric, peer-to-peer transfer of messages between two nodes and leaves routing to whatever broker or peer sits behind an address. That is why Azure Service Bus, ActiveMQ, and Qpid can all interoperate over AMQP 1.0 while implementing very different internals.
The difference shows up most clearly when you read the frames. In 0-9-1, the broker vocabulary is visible on the wire: clients issue methods such as exchange.declare, queue.bind, basic.publish, and basic.consume. A published message is then split into a method frame, a content header frame with properties and body size, and one or more body frames. In 1.0, the wire vocabulary is more abstract: peers open a connection, begin a session, attach sender or receiver links, exchange flow credit, transfer message sections, and settle deliveries with dispositions.
The 1.0 model nests three scopes: a connection carries one or more sessions, and each session carries one or more links. A link is unidirectional and has a role – a sender link or a receiver link – attached between a source and a target terminus. Messages travel as transfer frames along a link; the frames the chapter listed above (open, begin, attach, flow, transfer, disposition) are just the lifecycle of setting up and using those scopes.
That means migration is not a search-and-replace exercise. A RabbitMQ 0-9-1 producer might publish telemetry to a topic exchange with a routing key, where bindings choose the queue. An AMQP 1.0 producer instead attaches a sender link to an address; the broker decides what that address means. A packet capture therefore answers different questions. In 0-9-1 you ask, “Which exchange, queue, and method is this?” In 1.0 you ask, “Which connection/session/link is this transfer on, how much credit was available, and what delivery state settled it?”
7.4 Practitioner: Credit-Based Flow, and How the Two Versions Map
AMQP 1.0 flow control is credit-based and receiver-driven. A sender may not push at will: the receiver issues link credit in a flow frame, and the sender can emit only that many transfer frames before it must wait for more. This makes back-pressure explicit – a slow consumer simply stops granting credit. AMQP 0-9-1 achieves a similar effect differently, with basic.qos prefetch: the broker pushes up to a fixed number of unacknowledged messages and then pauses. Same goal, opposite direction: 1.0 receivers pull credit; 0-9-1 brokers push up to a cap.
Worked example: suppose a receiver link grants 25 credits. The sender can place 25 deliveries on that link and then must stop until another flow frame grants more credit. If the receiver processes 10 messages and grants 10 more credits, the sender gets room for 10 additional transfers without changing the TCP connection or creating a new link. The comparable 0-9-1 setting is basic.qos(prefetch_count=25), but the broker enforces that cap by withholding more pushed deliveries once 25 are outstanding.
| Concept | AMQP 0-9-1 (RabbitMQ) | AMQP 1.0 (OASIS/ISO) |
|---|---|---|
| Multiplexing unit | Channel | Session |
| Producer/consumer endpoint | Implicit in basic.publish / basic.consume |
Explicit sender/receiver link (attach) |
| Send a message | basic.publish (method+header+body frames) |
transfer frame |
| Flow control | Broker push, capped by prefetch | Receiver-granted link credit |
| Acknowledge | basic.ack / basic.nack |
disposition with a delivery state |
| Routing model | In the protocol (exchanges/queues/bindings) | Not in the protocol; broker-defined addresses |
For IoT gateways, this affects failure isolation. Put a high-rate telemetry stream and a low-rate command stream on separate links, and each link can have its own credit policy. Telemetry might keep 200 messages in flight because each sample is small and replaceable; commands might grant only one or two credits so the device handles each command deliberately. The session window still caps total in-flight transfers across links, so a gateway that multiplexes many devices should size link credit and session windows together rather than treating them as independent knobs.
7.5 Under the Hood: Settlement Is How 1.0 Chooses a Guarantee
In AMQP 1.0 each delivery is settled or unsettled, and a receiver reports an outcome in a disposition: terminal delivery states are accepted, rejected, released (send it to someone else), or modified (return it with annotations, e.g. increment a failure count). The two settlement-mode knobs on the link decide the guarantee:
- At-most-once: the sender pre-settles – fires the transfer and forgets it. Fast, may lose.
- At-least-once: the sender leaves the delivery unsettled until the receiver’s disposition confirms
accepted; a lost confirm means resend, so duplicates are possible. - Exactly-once: a two-phase settlement (
rcv-settle-mode = second) where the receiver settles only after the sender acknowledges the receiver’s outcome, so neither loss nor duplication occurs on that link.
Use those modes as engineering choices, not labels on a marketing slide. A temperature sample sent every few seconds may be acceptable as at-most-once because a later sample replaces it. A valve command should usually be unsettled until accepted, and the application should include a command id so a retry does not execute the same command twice. Two-phase settlement can remove ambiguity on the AMQP link, but side effects outside that link still need idempotency or transaction boundaries. For example, if a consumer accepts a delivery and then writes to a database, the database write and AMQP settlement are separate unless the system explicitly coordinates them.
This is a real difference from AMQP 0-9-1, which offers no native exactly-once settlement mode and pushes most systems toward at-least-once plus idempotent consumers. Sessions also carry their own flow window (incoming-window and outgoing-window) on top of per-link credit, so 1.0 does back-pressure at two levels: the session bounds total in-flight transfers, and each link bounds its own. When debugging a stalled link, inspect both numbers; a link can have credit and still be blocked if the session window is exhausted.