Settlement
What ack, retry, drop and retry_after become on a Redis stream, a reliable list, a simple
list and Pub/Sub.
The diagram as text
- Outcome: ack; retry; drop
- Stream: XACK; XADD copy, then XACK; XACK
- Claiming: XACK; stays pending; XACK
- Reliable: LREM; LPUSH, then LREM; LREM
- No ack: not supported; not supported; not supported
The runtime settles each delivery with the outcome its
handler returned, and the crate maps the outcome onto the form's own acknowledgement. A stream
acknowledges with XACK in the subscription's group. A reliable list removes the entry from its processing list with LREM. A
simple list and Pub/Sub have nothing to acknowledge, and settling there answers
AckError::Unsupported. The settle commands go out on the pool, not on the subscription's read
client.
A retry on a stream appends a copy of the entry to the same stream, then acknowledges the
original. A crash between the two leaves a duplicate, not a loss. A
claiming subscription retries through the
pending entries list instead. It appends and acknowledges nothing, and its next read claims the
entry back once it has been idle for min_idle, under the same id, with a delivery count one
higher. A reliable list pushes the entry back to its queue before it removes it from the
processing list.
Retries with a delay
The diagram as text
- Runtime copy: XACK the original; Copy held in the process: lost on a crash; XADD the copy when the timer fires
- Delay queue: retry_after(delay) on a stream entry; ZADD the copy, then XACK; In Redis, scored by its due time; A read sweeps it: XADD back to the stream
- Claiming: Stays in the pending entries list; Claimed back after min_idle
- retry_after(delay) on a stream entry → XACK the original
- retry_after(delay) on a stream entry → ZADD the copy, then XACK
- retry_after(delay) on a stream entry → Stays in the pending entries list
- XACK the original → Copy held in the process: lost on a crash
- Copy held in the process: lost on a crash → XADD the copy when the timer fires: delay
- ZADD the copy, then XACK → In Redis, scored by its due time
- In Redis, scored by its due time → A read sweeps it: XADD back to the stream: due
- Stays in the pending entries list → Claimed back after min_idle: idle
Redis has no per-entry delay, so a stream subscription serves
retry_after in one of three ways. By
default the runtime acknowledges the original and holds a copy, which it publishes back to the
stream when the delay is up. The copy's retry count is one higher. A crash before the timer fires
loses it.
delayed_retry with
DelayedRetry::DurableZset
keeps the copy in Redis. The copy is added to a
sorted set, scored by its due time, and then the original is acknowledged. Each read first moves
the copies that are due back onto the stream with XADD, at most 128 per read, so a delay is honoured to within one block interval. The scores are
wall-clock milliseconds, so the clocks of the services that share a queue should agree.
A claiming subscription leaves the entry pending, and its next read claims it back once
min_idle has passed. A delay shorter than min_idle waits min_idle.
A list and a Pub/Sub subscription take the runtime's copy, which goes back to the list or the channel. A pattern subscription names the destination of its copies at its mount site.
A max_attempts cap counts attempts with one of two numbers, and the form decides which. The
claiming and reclaim modes count with the server's delivery count from the pending entries list.
Every other form counts with the retry-count header that the copies carry, which the delay queue
raises on every round.