Skip to content

INCREX and ARGREP are routed by key on a cluster - #3352

Merged
mgravell merged 1 commit into
mainfrom
marc/increx-argrep-cluster-slot
Nov 12, 2026
Merged

mgravell merged 1 commit into
mainfrom
marc/increx-argrep-cluster-slot

Conversation

@mgravell

Copy link
Copy Markdown
Member

INCREX and ARGREP were not routed by their key on a cluster. This fixes both.

The problem

IncrexMessageBase (#3065) and ArrayGrepMessage (#3076) derive from Message directly, hold a RedisKey, and never override GetHashSlot, so they report NoSlot. On a cluster the command goes to an arbitrary node and depends on -MOVED:

  • with default flags the result is correct, but most calls take a second round trip;
  • with CommandFlags.NoRedirect the call fails: Key has MOVED to Endpoint 127.0.0.1:7001 and hashslot 9615 but CommandFlags.NoRedirect was specified - redirect not followed for INCREX.

Measured before the fix against the 6-node test cluster (3 primaries), 60 keys per row; the controls are single-key commands whose messages do carry a slot:

Call Flags OK MOVED error
INCRBY (control) NoRedirect 60 0
INCREX NoRedirect 21 39
INCREX default 60 0
ARGET (control) NoRedirect 60 0
ARGREP NoRedirect 20 40
ARGREP default 60 0

Affected surface: the StringIncrement/StringIncrementAsync overloads that take an Expiration, and ArrayGrep/ArrayGrepAsync.

The fix

Both classes now derive from Message.CommandKeyBase, as their single-key siblings do. That supplies the slot, and also puts the key in CommandAndKey for diagnostics. No public API change.

Tests

KeyedMessageSlotTests:

  • unit (no server): the INCREX long and double messages and the ARGREP message report the key's slot;
  • live (cluster, require: v8_8_0): 32 keys each under NoRedirect, so a call that misses the slot owner throws.

All 5 fail with the fix reverted and pass with it, on net10.0 and net8.0. The existing Increx* and Array* classes still pass (89 of 89 with the new tests, net10.0). The full suite and net481 were not run on this branch.

Not in scope

An audit of the other message kinds found no other keyed message without a slot. It did find multi-key commands where only one key is hashed (LMOVE, LMOVEM, ZRANGESTORE, GEOSEARCHSTORE, COPY ... DB, LCS ... IDX, LMPOP, ZMPOP, BITOP): same-slot calls route correctly, and cross-slot calls get the server's CROSSSLOT rather than the library's multi-slot exception. Those are deliberately left alone here.

IncrexMessageBase (#3065) and ArrayGrepMessage (#3076) derived from Message
directly, held a key, and never overrode GetHashSlot, so they reported
NoSlot. On a cluster that sends the command to an arbitrary node and leans
on -MOVED: an extra round trip for most calls, and a RedisServerException
under CommandFlags.NoRedirect.

Both now derive from Message.CommandKeyBase, as their single-key siblings
do, which supplies the slot (and the key in CommandAndKey).

Affects the StringIncrement overloads that take an Expiration (INCREX) and
ArrayGrep. No public API change.
@mgravell
mgravell merged commit 30ae6b9 into main Nov 12, 2026
5 checks passed
@mgravell
mgravell deleted the marc/increx-argrep-cluster-slot branch November 12, 2026 16:27
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