Skip to content

fix(cluster): split a cross-slot SUNSUBSCRIBE per slot - #132

Merged
mcatanzariti merged 1 commit into
mainfrom
claude/new-session-t40qkv
Nov 14, 2026
Merged

mcatanzariti merged 1 commit into
mainfrom
claude/new-session-t40qkv

Conversation

@mcatanzariti

Copy link
Copy Markdown
Member

Problem

A single SSUBSCRIBE must name one slot, but a PubSubStream may add shard channels of other slots afterwards through PubSubStream::ssubscribe. close and Drop then released them all in one SUNSUBSCRIBE, which the cluster connection routed as a single-slot command and refused at feed time with MismatchedKeySlots:

  • close returned the error;
  • Drop swallowed it (fire-and-forget);
  • every subscription stayed on its master and in the client's registry;
  • the next ssubscribe on the same Client stalled (observed: the new test hangs on main).

Note: the reported reproduction (client.ssubscribe(["doc:{a}", "doc:{b}"])) actually fails earlier, at the subscription itself, with MismatchedKeySlots. The leak happens when a stream accumulates slots one ssubscribe at a time.

Fix

A SUNSUBSCRIBE naming several slots is routed through the multi-shard policy, one slice per slot (not per node: Redis refuses a cross-slot SUNSUBSCRIBE even when both slots live on the same node). The router matches acknowledgements per channel, so the caller is answered once every master has confirmed. A single-slot SUNSUBSCRIBE keeps the cheaper single-shard path.

Tests

  • dropping_a_shard_stream_spanning_slots_releases_every_slot_in_cluster: drop, re-subscribe, and check messages arrive from both masters. Hangs on main, passes here.
  • closing_a_shard_stream_spanning_slots_succeeds_in_cluster: close and an explicit cross-slot sunsubscribe. Fails on main, passes here.
  • ./run_tests.sh --hermetic and clippy clean. Pub/sub and cluster suites run against a local 3-master cluster: no new failure (the remaining ones need replicas / spare nodes / Redis 8 and fail identically on main).

Generated by Claude Code

A single SSUBSCRIBE must name one slot, but a PubSubStream may add shard
channels of other slots afterwards through `PubSubStream::ssubscribe`.
`close` and `Drop` then released them all in one SUNSUBSCRIBE, which the
cluster connection routed as a single-slot command and refused at feed time
with `MismatchedKeySlots`. `close` returned the error, `Drop` swallowed it,
every subscription stayed on its master, and the next command on the same
client could stall.

A SUNSUBSCRIBE naming several slots is now routed through the multi-shard
policy, one slice per slot. The acknowledgements are matched per channel by
the router, so the caller is answered once every master has confirmed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo8jBqM8KTsnpJz9oRkK5G
@mcatanzariti
mcatanzariti merged commit 3c28ac8 into main Nov 14, 2026
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant