Skip to main content

Settlement

What ack, drop, retry and retry_after become on AMQP 1.0: a disposition the broker acts on, and copies the runtime publishes to the same address.

Each outcome of a handler on an at-least-once subscription: the disposition the subscription sends and what the broker doesHandlerDispositionBrokerack()accepteddone: themessage leavesthe queueretry()modifieddelivery-failedback on thequeue, countedone moreretry_after(d)rejected,a copy after dthe copy is anew message onthe addressdrop()rejectedthe broker'sdead-letterpolicy decidesno outcomebefore thelink goesnothingback on thequeue when thelink detachesAt most once, deliveries arrive settled: ack, retryand drop report AckError::Unsupported
The diagram as text
  1. Handler: ack(); retry(); retry_after(d); drop(); no outcome before the link goes
  2. Disposition: accepted; modified delivery-failed; rejected, a copy after d; rejected; nothing
  3. Broker: done: the message leaves the queue; back on the queue, counted one more; the copy is a new message on the address; the broker's dead-letter policy decides; back on the queue when the link detaches
  4. ack() → accepted
  5. accepted → done: the message leaves the queue
  6. retry() → modified delivery-failed
  7. modified delivery-failed → back on the queue, counted one more
  8. retry_after(d) → rejected, a copy after d
  9. rejected, a copy after d → the copy is a new message on the address
  10. drop() → rejected
  11. rejected → the broker's dead-letter policy decides
  12. no outcome before the link goes → nothing
  13. nothing → back on the queue when the link detaches
  14. At most once, deliveries arrive settled: ack, retry and drop report AckError::Unsupported

A subscription is at least once by default. A delivery stays unsettled until the handler's outcome reaches the pump task as a disposition. A delivery that never gets one stays on the link, and the broker returns it to the queue when the link detaches or the connection drops.

A retry() sends modified with delivery-failed, never released. A release tells the broker the delivery was not acted on, and it leaves delivery-count as it was. A handler that asks for a retry did act on it and failed, and an attempt cap reads that count: without the increment a message that always fails would come back forever. undeliverable-here stays false, so the message may come back to this same subscription.

Settle::AtMostOnce settles each delivery as it arrives.

OutcomeAt most once
ack, dropAckError::Unsupported, logged: the delivery was settled on arrival
retry()AckError::Unsupported; under a declared cap, a copy at once where the delivery carries no delivery-count
retry_after(d)a copy published to the address after d
no outcomenothing: the broker already let the message go

How many times a message has been delivered is delivery-count + 1, which redelivery_count reports. A message this crate published has no header section, so it carries no count, and the framework's retry-count header counts for it.

Retries​

A retry on AMQP 1.0: the attempt cap decides between bringing the message back, the dead-letter address and a rejectionA delivery: its attempt is delivery-count + 1,or x-ruststream-retry-count on a copyThe handler returnsretry() or retry_after(delay)max_attempts: is this attempt below the cap?retry():modified,back onthe queueretry_after:rejected,a copy afterthe delayAt the cap:a copy tothe dead-letteraddressAt the cap,no deadletter:rejectedBoth come back tothe subscription's addressA copy waits for its delay inside the process:a stop before the timer fires loses it
The diagram as text
  1. A delivery: its attempt is delivery-count + 1, or x-ruststream-retry-count on a copy → The handler returns retry() or retry_after(delay): handled
  2. The handler returns retry() or retry_after(delay) → max_attempts: is this attempt below the cap?: a retry
  3. max_attempts: is this attempt below the cap? → retry(): modified, back on the queue: below
  4. max_attempts: is this attempt below the cap? → retry_after: rejected, a copy after the delay
  5. max_attempts: is this attempt below the cap? → At the cap: a copy to the dead- letter address: at the cap
  6. max_attempts: is this attempt below the cap? → At the cap, no dead letter: rejected
  7. retry(): modified, back on the queue → Both come back to the subscription's address
  8. retry_after: rejected, a copy after the delay → Both come back to the subscription's address
  9. A copy waits for its delay inside the process: a stop before the timer fires loses it

The cap is declared at the mount site with max_attempts, and the first delivery counts as one. Below the cap, a retry() goes back to the broker with modified, and the broker counts it. A copy carries no count of the broker's, so under a cap a retry() of a copy publishes the next copy at once.

AMQP 1.0 holds no message back, so a retry_after is the runtime's own. It rejects the delivery, waits for the delay, and publishes a copy with the retry-count header raised by one. The copy goes to the subscription's own address, because one node is where a receiver attaches its source and a sender its target. On a queue address the copy competes for receivers like any other message, and on a topic address every subscription receives it.

At the cap, the delivery is published as it arrived to the dead-letter address. With no dead-letter address declared it is rejected, and the broker's own dead-letter policy decides. A dead-letter address declared without a cap takes every retry.