Skip to content

Fix CROSSSLOT in lock renewal for useSingleServer() behind a cluster proxy#7114

Open
govansmailbox wants to merge 1 commit into
redisson:masterfrom
govansmailbox:fix/single-connection-manager-calc-slot-cluster-detected
Open

Fix CROSSSLOT in lock renewal for useSingleServer() behind a cluster proxy#7114
govansmailbox wants to merge 1 commit into
redisson:masterfrom
govansmailbox:fix/single-connection-manager-calc-slot-cluster-detected

Conversation

@govansmailbox

@govansmailbox govansmailbox commented May 7, 2026

Copy link
Copy Markdown

When Redisson is configured with useSingleServer() pointing at a proxy that fronts a Redis Cluster, the existing cluster-detection mechanism (874588f) correctly sets clusterDetected=true via a Lua CROSSSLOT probe.

However, once detected, the lock renewal path (RenewalTask) switches to the cluster branch and groups locks by slot using calcSlot(). The problem: SingleConnectionManager never overrode calcSlot(), so it fell through to MasterSlaveConnectionManager which always returned singleSlotRange.getStartSlot() (effectively 0). This collapsed every lock key into slot 0, causing the renewal to send one Lua script containing all lock keys to the proxy. The proxy routed it to one backend node which saw keys from multiple real cluster slots and threw CROSSSLOT -- the same error the detection was meant to prevent.

Fix:

  • Override calcSlot(String), calcSlot(byte[]) and calcSlot(ByteBuf) in SingleConnectionManager to compute real Redis cluster CRC16 hash-slot values (including hash-tag extraction) when clusterSetup is detected. In non-cluster single-server mode the existing behaviour (slot 0) is preserved.
  • Extract the shared CRC16 + hash-tag slot-calculation logic into a new package-private helper SlotCalculator so that both ClusterConnectionManager and SingleConnectionManager use one canonical implementation with no duplication.

Tests:

  • Added SlotCalculatorTest covering: null safety, plain keys, hash-tag extraction, invalid/edge-case tags (empty {}, unclosed brace), multiple brace pairs (first tag wins), cross-overload consistency (String / byte[] / ByteBuf produce identical slots), slot range validity [0,16384) and ByteBuf non-destructive read (readerIndex unchanged). All 29 tests pass.

Fixes: #7116

@govansmailbox
govansmailbox force-pushed the fix/single-connection-manager-calc-slot-cluster-detected branch from 2d9ad82 to 5602659 Compare May 7, 2026 10:24
…proxy

When Redisson is configured with useSingleServer() pointing at a proxy
that fronts a Redis Cluster, the existing cluster-detection mechanism
(874588f) correctly sets clusterDetected=true via a Lua CROSSSLOT probe.

However, once detected, the lock renewal path (RenewalTask) switches to
the cluster branch and groups locks by slot using calcSlot(). The problem:
SingleConnectionManager never overrode calcSlot(), so it fell through to
MasterSlaveConnectionManager which always returned singleSlotRange.getStartSlot()
(effectively 0). This collapsed every lock key into slot 0, causing the
renewal to send one Lua script containing all lock keys to the proxy.
The proxy routed it to one backend node which saw keys from multiple real
cluster slots and threw CROSSSLOT -- the same error the detection was
meant to prevent.

Fix:
- Override calcSlot(String), calcSlot(byte[]) and calcSlot(ByteBuf) in
  SingleConnectionManager to compute real Redis cluster CRC16 hash-slot
  values (including hash-tag extraction) when clusterSetup is detected.
  In non-cluster single-server mode the existing behaviour (slot 0) is
  preserved.
- Extract the shared CRC16 + hash-tag slot-calculation logic into a new
  package-private helper SlotCalculator so that both
  ClusterConnectionManager and SingleConnectionManager use one canonical
  implementation with no duplication.

Tests:
- Added SlotCalculatorTest covering: null safety, plain keys, hash-tag
  extraction, invalid/edge-case tags (empty {}, unclosed brace), multiple
  brace pairs (first tag wins), cross-overload consistency (String /
  byte[] / ByteBuf produce identical slots), slot range validity [0,16384)
  and ByteBuf non-destructive read (readerIndex unchanged).
  All 29 tests pass.

Fixes: redisson#7017

Signed-off-by: Elangovan G <govansmailbox@gmail.com>
Signed-off-by: Elangovan G <eg@egP9M7G.omnissa.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

CROSSSLOT error in lock renewal when useSingleServer() points to a cluster proxy

1 participant