Settlement
What ack, drop, retry and retry_after become on
ZeroMQ, which settles nothing: an ack answers Unsupported, and a retry is a copy the service
publishes.
The diagram as text
- Handler: ack(); retry(); retry_after(d); drop()
- Delivery: AckError:: Unsupported; AckError:: Unsupported; a copy after d; AckError:: Unsupported
- Message: done: there is nothing to settle; gone, unless a cap is declared: then a copy; the copy is a new message, counted; gone
- ack() → AckError:: Unsupported
- AckError:: Unsupported → done: there is nothing to settle
- retry() → AckError:: Unsupported
- AckError:: Unsupported → gone, unless a cap is declared: then a copy
- retry_after(d) → a copy after d
- a copy after d → the copy is a new message, counted
- drop() → AckError:: Unsupported
- AckError:: Unsupported → gone
- Delivery is at most once: a message the handler does not finish is not delivered again
A ZeroMQ socket hands a message over and forgets it. There is no acknowledgement in the protocol,
so ack and nack on a ZmqMessage answer
AckError::Unsupported at once. The runtime logs that answer as a warning, and the message is
done either way.
A plain retry() delivers nothing again, and the handler is not called a second time. A
registration that declares max_attempts or a
dead-letter destination turns retry() into a copy,
as for retry_after.
ZeroMQ counts no deliveries, so redelivery_count is empty and the runtime counts the attempts
itself. The count travels in the copy's x-ruststream-retry-count header, and the first delivery
counts as one.
Retries
The diagram as text
- A delivery x-ruststream-retry-count says which attempt it is → The handler returns retry_after(delay), or retry() under a cap: handled
- The handler returns retry_after(delay), or retry() under a cap → max_attempts: is this attempt below the cap?: a retry
- max_attempts: is this attempt below the cap? → Bound: a copy to its own listener: below
- max_attempts: is this attempt below the cap? → Dialing or responder: a copy to a named place
- max_attempts: is this attempt below the cap? → At the cap: a copy to the dead- letter name: at the cap
- max_attempts: is this attempt below the cap? → At the cap, no dead letter: dropped
- Bound: a copy to its own listener → The copy is a new message, one more attempt
- Dialing or responder: a copy to a named place → The copy is a new message, one more attempt
- A copy waits for its delay inside the process: a crash before the timer fires loses it
A retry_after outcome waits for the delay inside the process, then publishes a copy through the
registration's retry publisher. Where the copy goes
depends on the pattern and on the side of the endpoint, and the type states it.
A ZmqQueue or
ZmqFanout subscription that binds its endpoint reports its
own name as the address. The retry publisher dials the subscription's own listener, and the copy
arrives there as the next attempt. The mount site names nothing.
A subscription that dials reads from a peer that only sends. A
ZmqRpc responder's name is not a destination: its publisher
sends only to the identities requests carry. Neither has an address for a copy, so the mount site
names where the copies go, usually a queue the service binds for itself. A router chain that names no destination does not compile, and a
registration that names none is refused at startup.
At the cap, the delivery goes to the dead-letter destination through the same publisher, so the destination belongs to a publisher on another endpoint. On the endpoint a queue subscription binds, a dead letter would come back to that subscription: the publisher refuses it, and the delivery is dropped. On a bound fan-out, a dead-letter name under the subscription's prefix arrives back at it. With no dead-letter destination the delivery is dropped, with a warning.