Skip to content

Conversation

@uglide
Copy link
Contributor

@uglide uglide commented Jan 21, 2026

This PR introduces support for request/response policies in Redis cluster command execution, enabling proper handling of keyless commands and multi-shard operations. The changes implement Redis's command tips specification for cluster deployments, allowing the Jedis client to intelligently route commands to appropriate nodes and aggregate responses based on command-specific policies.

Key Changes

Core Infrastructure

  • CommandFlagsRegistry: Added RequestPolicy and ResponsePolicy enums to define how commands should be routed and how responses should be aggregated in cluster mode
  • StaticCommandFlagsRegistry: Extended to store and retrieve request/response policies alongside command flags
  • CommandArguments: Added isKeyless() method and addHashSlotKey() for special cases like KEYS/SCAN commands; removed ClusterCommandArguments in favor of unified hash slot tracking

Cluster Command Execution

  • ClusterCommandExecutor:
    • Added executeKeylessCommand() with round-robin distribution across cluster nodes
    • Added executeMultiShardCommand() for commands that span multiple hash slots (DEL, MGET, MSET, etc.)
    • Enhanced broadcastCommand() to support both primary-only and all-nodes execution
    • Integrated request policy routing in executeCommand()
  • ClusterReplyAggregator: New utility class implementing response aggregation strategies (SUM, MIN, MAX, LOGICAL_AND, LOGICAL_OR, ALL_SUCCEEDED, ONE_SUCCEEDED)

Multi-Shard Command Support

  • ClusterCommandObjects: Added methods to split multi-key commands by hash slot:
    • delMultiShard(), existsMultiShard(), mgetMultiShard(), msetMultiShard()
    • touchMultiShard(), unlinkMultiShard(), msetexMultiShard()
    • Helper methods groupArgumentsByKeyHashSlot() and groupArgumentsByKeyValueHashSlot()

Code Generation

  • CommandFlagsRegistryGenerator: Updated to extract request_policy and response_policy from Redis command tips, with support for manual overrides

Exception Handling

  • Added UnsupportedAggregationException for invalid aggregation operations
  • Added ClusterAggregationException for aggregation failures

Impact

  • Keyless commands (e.g., DBSIZE, CONFIG GET) are now properly distributed across cluster nodes using round-robin
  • Multi-key commands (e.g., DEL, MGET, MSET) with keys in different hash slots are automatically split and executed across appropriate shards
  • Response aggregation is handled according to Redis specifications (sum for DBSIZE, logical AND for SCRIPT EXISTS, etc.)
  • Read-only keyless commands can be routed to replicas for better load distribution
  • Removed ClusterCommandArguments class - hash slot tracking is now unified in CommandArguments

Breaking Changes

  • CommandExecutor interface: Removed broadcastCommand() default method - implementations should use ClusterCommandExecutor.broadcastCommand(commandObject, primaryOnly) directly
  • ClusterCommandArguments: Deleted - use CommandArguments with getKeyHashSlots() instead
  • JedisBroadcastAndRoundRobinConfig: Removed (functionality integrated into executor)

Fixes: #990

@uglide uglide force-pushed the im/request-response-policy-support branch from 412a50f to d03b783 Compare January 21, 2026 15:31
@uglide uglide force-pushed the im/request-response-policy-support branch from a957982 to 0db6694 Compare January 21, 2026 15:41
@uglide uglide force-pushed the im/request-response-policy-support branch from bd6ee0f to 0fdcacf Compare January 21, 2026 16:23
@uglide uglide added the breakingchange Pull request that has breaking changes. Must include the breaking behavior in release notes. label Jan 21, 2026
@uglide uglide added this to the 8.0.0 milestone Jan 21, 2026
@uglide uglide requested review from Copilot and ggivo January 22, 2026 10:54
@github-actions
Copy link

github-actions bot commented Jan 22, 2026

Test Results

   287 files  + 2     287 suites  +2   12m 18s ⏱️ +14s
10 524 tests +55  10 466 ✅ +256  58 💤  - 201  0 ❌ ±0 
 2 829 runs  +55   2 825 ✅ + 55   4 💤 ±  0  0 ❌ ±0 

Results for commit 6bfffe6. ± Comparison against base commit af6454d.

This pull request removes 33 and adds 88 tests. Note that renamed tests count towards both.
redis.clients.jedis.commands.unified.client.RedisClientAllKindOfValuesCommandsTest[1] ‑ sendBlockingCommandTest
redis.clients.jedis.commands.unified.client.RedisClientAllKindOfValuesCommandsTest[1] ‑ sendCommandTest
redis.clients.jedis.commands.unified.client.RedisClientAllKindOfValuesCommandsTest[2] ‑ sendBlockingCommandTest
redis.clients.jedis.commands.unified.client.RedisClientAllKindOfValuesCommandsTest[2] ‑ sendCommandTest
redis.clients.jedis.commands.unified.client.RedisClientAllKindOfValuesCommandsTest[3] ‑ sendBlockingCommandTest
redis.clients.jedis.commands.unified.client.RedisClientAllKindOfValuesCommandsTest[3] ‑ sendCommandTest
redis.clients.jedis.commands.unified.client.RedisClientBinaryValuesCommandsTest[1] ‑ sendBlockingCommandTest
redis.clients.jedis.commands.unified.client.RedisClientBinaryValuesCommandsTest[1] ‑ sendCommandTest
redis.clients.jedis.commands.unified.client.RedisClientBinaryValuesCommandsTest[2] ‑ sendBlockingCommandTest
redis.clients.jedis.commands.unified.client.RedisClientBinaryValuesCommandsTest[2] ‑ sendCommandTest
…
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandCircularCounterNeverOverflows
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandEvenDistributionRoundRobin
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandFailsAfterMaxAttempts
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandFailsWithEmptyConnectionMap
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandIgnoresRedirections
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandRoundRobinDistribution
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandRoundRobinSequence
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandUsesConnectionMapRoundRobin
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandWithReadOnlyCommandUsesAllNodesConnectionMap
redis.clients.jedis.ClusterCommandExecutorTest ‑ runKeylessCommandWithWriteCommandUsesPrimaryNodesConnectionMap
…

♻️ This comment has been updated with latest results.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces comprehensive support for Redis cluster request/response policies, enabling intelligent routing of keyless commands and multi-shard operations. The changes implement Redis's command tips specification for cluster deployments.

Changes:

  • Added RequestPolicy and ResponsePolicy enums with intelligent routing and aggregation strategies
  • Implemented keyless command execution with round-robin distribution across cluster nodes
  • Added multi-shard command support with automatic key-based slot splitting
  • Removed ClusterCommandArguments in favor of unified hash slot tracking in CommandArguments

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Test files (multiple) Updated from broadcastCommand() to executeCommand() - proper API migration
ClusterReplyAggregatorTest.java Comprehensive tests for new aggregation utility
ClusterCommandExecutorTest.java Extensive tests for keyless and multi-shard execution
ClusterCommandObjectsTest.java Tests for hash slot grouping logic
CommandFlagsRegistryGenerator.java Extracts request/response policies from Redis command metadata
ClusterCommandExecutor.java Core policy-based routing implementation
ClusterReplyAggregator.java Response aggregation utility (SUM, MIN, MAX, AND, OR, etc.)
CommandArguments.java Added hash slot tracking with caching
ClusterCommandObjects.java Multi-shard command splitting methods
RedisClusterClient.java Multi-shard method overrides (del, mget, mset, etc.)
StaticCommandFlagsRegistry*.java Policy storage and lookup
UnifiedJedis.java Removed broadcast config, deprecated sendCommand methods
ClusterCommandArguments.java Deleted - functionality merged into CommandArguments

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


slotToElements.computeIfAbsent(slot, k -> new ArrayList<>()).add(key);
if (keyValueMode) {
slotToElements.get(slot).add(keysOrKeysValues[i + 1]);
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This array access might be out of bounds, as the index might be equal to the array length.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breakingchange Pull request that has breaking changes. Must include the breaking behavior in release notes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for high level cluster commands

2 participants