Window
A pipelined subscription settles in a window: the deliveries of a read queue their side effects, and one flush sends them with the settles.
The diagram as text
- One flush, one round trip: INCR of 1-0; INCR of 3-0; XACK 1-0 2-0 3-0
- Entry 1-0 queues an INCR → ack: segment kept
- ack: segment kept → INCR of 1-0
- Entry 2-0 queues an INCR → drop: segment dropped
- drop: segment dropped → XACK 1-0 2-0 3-0: settle only
- Entry 3-0 queues an INCR → ack: segment kept
- ack: segment kept → INCR of 3-0
- Under .atomic() each segment is MULTI, its commands, the delivery's own settle, then EXEC
.pipeline() at the mount site
opens a window over the subscription. Each delivery of a read takes a slot in it. What its handler
queues through Ctx<keys::Pipeline> goes into the slot's segment, a fred pipeline opened at the
first queued command. The handler does not see the command's reply.
The outcome decides the segment: ack keeps it, and drop, retry and retry_after drop it.
Each outcome sends the settle the form sends without a window. A delivery dropped unsettled sends
no settle: its segment goes, and its entry stays pending.
A window flushes when the settled deliveries reach the read's COUNT, when nothing is outstanding,
or when the subscription stops. The flush sends the kept segments in the order they were committed,
then the settles of the read in one pipeline, on a connection of the pool. A stream's settles leave
as one XACK, and a reliable list's as one LREM per entry. Under load that is one round trip per
read.
.atomic() wraps each segment in
MULTI and EXEC and puts the delivery's own settle inside it. The handler's side effects and
its acknowledgement then take effect together. Redis has no rollback: a command that fails inside
EXEC leaves the others executed
(transactions). On a cluster
every key of a segment has to share the slot of the subscription's key.
A flush that fails is reported once on the delivery stream. On the forms that settle, an entry whose settle failed stays pending and is delivered again.