Skip to content

feat(cluster): split a cross-slot SSUBSCRIBE per slot - #134

Merged
mcatanzariti merged 1 commit into
mainfrom
claude/ssubscribe-split-per-slot
Nov 14, 2026
Merged

mcatanzariti merged 1 commit into
mainfrom
claude/ssubscribe-split-per-slot

Conversation

@mcatanzariti

Copy link
Copy Markdown
Member

Problem

The server requires one slot per SSUBSCRIBE, and the client refused a cross-slot one with MismatchedKeySlots. So client.ssubscribe(["doc:{a}", "doc:{b}"]), the exact reproduction of the original report, failed outright, while the matching SUNSUBSCRIBE has been split per slot since #132.

Change

A shard subscription is per channel, so nothing is atomic about subscribing to several at once. A SSUBSCRIBE naming several slots is now routed like a cross-slot SUNSUBSCRIBE: one slice per slot, each to the master owning it (through the route classifier from #133, so check_routable accepts it too). The router matches confirmations by name, so the caller is answered once every master has confirmed.

The documentation of PubSubCommands::ssubscribe described SUBSCRIBE and linked to it; it now describes shard channels and the per-slot split.

Listed under Changed in the changelog: it is a visible behaviour change (an error became a success), not a fix.

Trade-off

As with a plain SUBSCRIBE, which is already split per node, a hard failure on one slice (not a redirection, which the multi-shard path replays) can leave the other slices subscribed while the caller gets an error. Refusing cross-slot subscriptions outright avoided that, at the cost of the API the report expected.

Tests

  • a_cross_slot_ssubscribe_is_split_per_slot_in_cluster: the report's reproduction run to the end. It subscribes to two slots on two masters, receives from both, drops, waits until no master holds the channels, and repeats. Fails on main with MismatchedKeySlots, passes here.
  • It replaces a_refused_cross_slot_ssubscribe_leaves_the_client_usable from fix(cluster): refuse an unroutable command before recording anything #133, whose premise (a refused SSUBSCRIBE) no longer exists. The routing-refusal path is still covered by a_pipeline_with_a_cross_slot_command_runs_nothing.
  • Clippy -D warnings, ./run_tests.sh --hermetic, and the cross-slot and pub/sub tests on a local 3-master cluster pass.

Generated by Claude Code

The server requires one slot per SSUBSCRIBE, and the client refused a
cross-slot one with `MismatchedKeySlots`. A shard subscription is per
channel, so nothing is atomic about subscribing to several at once: the
command is now cut per slot like SUNSUBSCRIBE already is, each slice going
to the master owning its slot. The router matches confirmations by name, so
the caller is answered once every master has confirmed.

The documentation of `PubSubCommands::ssubscribe` described SUBSCRIBE and
linked to it; it now describes shard channels and the per-slot split.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo8jBqM8KTsnpJz9oRkK5G
@mcatanzariti
mcatanzariti merged commit afe1cbb 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