@@ -121,6 +121,11 @@ type ClusterOptions struct {
121121
122122 TLSConfig * tls.Config
123123
124+ // DisableRoutingPolicies disables the request/response policy routing system.
125+ // When disabled, all commands use the legacy routing behavior.
126+ // Experimental. Will be removed when shard picker is fully implemented.
127+ DisableRoutingPolicies bool
128+
124129 // DisableIndentity - Disable set-lib on connect.
125130 //
126131 // default: false
@@ -939,6 +944,29 @@ func (c *clusterState) slotRandomNode(slot int) (*clusterNode, error) {
939944 return nodes [randomNodes [0 ]], nil
940945}
941946
947+ func (c * clusterState ) slotShardPickerSlaveNode (slot int , shardPicker routing.ShardPicker ) (* clusterNode , error ) {
948+ nodes := c .slotNodes (slot )
949+ if len (nodes ) == 0 {
950+ return c .nodes .Random ()
951+ }
952+
953+ // nodes[0] is master, nodes[1:] are slaves
954+ // First, try all slave nodes for this slot using ShardPicker order
955+ slaves := nodes [1 :]
956+ if len (slaves ) > 0 {
957+ for i := 0 ; i < len (slaves ); i ++ {
958+ idx := shardPicker .Next (len (slaves ))
959+ slave := slaves [idx ]
960+ if ! slave .Failing () && ! slave .Loading () {
961+ return slave , nil
962+ }
963+ }
964+ }
965+
966+ // All slaves are failing or loading - return master
967+ return nodes [0 ], nil
968+ }
969+
942970func (c * clusterState ) slotNodes (slot int ) []* clusterNode {
943971 i := sort .Search (len (c .slots ), func (i int ) bool {
944972 return c .slots [i ].end >= slot
@@ -1096,7 +1124,11 @@ func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
10961124
10971125 if node == nil {
10981126 var err error
1099- node , err = c .cmdNode (ctx , cmd .Name (), slot )
1127+ if ! c .opt .DisableRoutingPolicies && c .opt .ShardPicker != nil {
1128+ node , err = c .cmdNodeWithShardPicker (ctx , cmd .Name (), slot , c .opt .ShardPicker )
1129+ } else {
1130+ node , err = c .cmdNode (ctx , cmd .Name (), slot )
1131+ }
11001132 if err != nil {
11011133 return err
11021134 }
@@ -1109,8 +1141,11 @@ func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
11091141 _ = pipe .Process (ctx , cmd )
11101142 _ , lastErr = pipe .Exec (ctx )
11111143 } else {
1112- // Execute the command on the selected node
1113- lastErr = c .routeAndRun (ctx , cmd , node )
1144+ if ! c .opt .DisableRoutingPolicies {
1145+ lastErr = c .routeAndRun (ctx , cmd , node )
1146+ } else {
1147+ lastErr = node .Client .Process (ctx , cmd )
1148+ }
11141149 }
11151150
11161151 // If there is no error - we are done.
@@ -2098,13 +2133,33 @@ func (c *ClusterClient) cmdNode(
20982133 return nil , err
20992134 }
21002135
2136+ if c .opt .ReadOnly {
2137+ cmdInfo := c .cmdInfo (ctx , cmdName )
2138+ if cmdInfo != nil && cmdInfo .ReadOnly {
2139+ return c .slotReadOnlyNode (state , slot )
2140+ }
2141+ }
2142+ return state .slotMasterNode (slot )
2143+ }
2144+
2145+ func (c * ClusterClient ) cmdNodeWithShardPicker (
2146+ ctx context.Context ,
2147+ cmdName string ,
2148+ slot int ,
2149+ shardPicker routing.ShardPicker ,
2150+ ) (* clusterNode , error ) {
2151+ state , err := c .state .Get (ctx )
2152+ if err != nil {
2153+ return nil , err
2154+ }
2155+
21012156 // For keyless commands (slot == -1), use ShardPicker to select a shard
21022157 // This respects the user's configured ShardPicker policy
21032158 if slot == - 1 {
21042159 if len (state .Masters ) == 0 {
21052160 return nil , errClusterNoNodes
21062161 }
2107- idx := c . opt . ShardPicker .Next (len (state .Masters ))
2162+ idx := shardPicker .Next (len (state .Masters ))
21082163 return state .Masters [idx ], nil
21092164 }
21102165
@@ -2124,6 +2179,11 @@ func (c *ClusterClient) slotReadOnlyNode(state *clusterState, slot int) (*cluste
21242179 if c .opt .RouteRandomly {
21252180 return state .slotRandomNode (slot )
21262181 }
2182+
2183+ if c .opt .ShardPicker != nil {
2184+ return state .slotShardPickerSlaveNode (slot , c .opt .ShardPicker )
2185+ }
2186+
21272187 return state .slotSlaveNode (slot )
21282188}
21292189
0 commit comments