Skip to main content

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.

One read of a pipelined stream subscription: each delivery queues a command, the outcome keeps or drops it, and one flush sends the restOne flush, one round tripEntry 1-0queues an INCRack:segment keptEntry 2-0queues an INCRdrop:segment droppedEntry 3-0queues an INCRack:segment keptINCR of 1-0INCR of 3-0XACK 1-0 2-0 3-0Under .atomic() each segment is MULTI, its commands,the delivery's own settle, then EXEC
The diagram as text
  1. One flush, one round trip: INCR of 1-0; INCR of 3-0; XACK 1-0 2-0 3-0
  2. Entry 1-0 queues an INCR → ack: segment kept
  3. ack: segment kept → INCR of 1-0
  4. Entry 2-0 queues an INCR → drop: segment dropped
  5. drop: segment dropped → XACK 1-0 2-0 3-0: settle only
  6. Entry 3-0 queues an INCR → ack: segment kept
  7. ack: segment kept → INCR of 3-0
  8. 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.