Skip to content

Commit bd21b27

Browse files
nirchetritrueian
andcommitted
feat: Add MaxMovedRedirections option to prevent infinite redirect loops (#92)
* implement MovedRetries Signed-off-by: nirchetrit <[email protected]> * - Changed module path from github.com/valkey-io/valkey-go to github.com/nirchetrit/valkey-go - Added dependency for github.com/valkey-io/valkey-go v1.0.67 - Removed indirect dependencies for github.com/kr/pretty and github.com/kr/text Signed-off-by: nirchetrit <[email protected]> * update module path from github.com/nirchetrit/valkey-go to github.com/valkey-io/valkey-go Signed-off-by: nirchetrit <[email protected]> * added MaxMovedRetries to the readme Signed-off-by: nirchetrit <[email protected]> * Implement MaxMovedRetries logic in DoMulti and DoMultiCache methods, ensuring proper error handling and retry behavior. Update README to clarify the behavior of MaxMovedRetries for multi-command operations. Signed-off-by: nirchetrit <[email protected]> * Update module path from github.com/valkey-io/valkey-go to github.com/nirchetrit/valkey-go Signed-off-by: nirchetrit <[email protected]> * Refactor MaxMovedRetries handling in DoMulti and DoMultiCache methods to use a local movedRetries counter. This improves error handling for exceeded retry limits and ensures consistent behavior across retry attempts. Signed-off-by: nirchetrit <[email protected]> * Update module path from github.com/nirchetrit/valkey-go to github.com/valkey-io/valkey-go and remove outdated dependencies. Adjust golang.org/x/tools version to v0.28.0. Signed-off-by: nirchetrit <[email protected]> * Revert changes to README.md Signed-off-by: nirchetrit <[email protected]> * Rename MaxMovedRetries to MaxMovedRedirections and update related error handling in cluster and test files for consistency. Signed-off-by: nirchetrit <[email protected]> * Enhance error handling for MaxMovedRedirections in cluster.go by refining the condition checks for ValkeyError. This ensures that errors related to moved keys are correctly identified and handled during retries. Signed-off-by: nirchetrit <[email protected]> * Clarify comments in cluster.go regarding error handling for MOVED responses during retries. This enhances code readability and maintains consistency with previous error handling updates. Signed-off-by: nirchetrit <[email protected]> * Rename MaxMovedRedirections to MaxRedirects and handle ASK redirections. expose the last received error instead of a generic max moved errors exceeded Signed-off-by: nirchetrit <[email protected]> * Add tests for handling ASK and MOVED errors in cluster client This commit introduces multiple test cases in cluster_test.go to validate the behavior of the cluster client when exceeding the maximum allowed ASK retries and handling mixed MOVED and ASK errors. The tests ensure that the client correctly identifies and returns ValkeyError for these scenarios, enhancing the robustness of error handling in the client. The new tests cover: - Exceeding max ASK retries for Do, DoCache, DoMulti, and DoMultiCache methods. - Handling mixed MOVED and ASK errors during retries. These additions improve the overall reliability of the cluster client in error-prone situations. Signed-off-by: nirchetrit <[email protected]> * revert go.mod Signed-off-by: Rueian <[email protected]> --------- Signed-off-by: nirchetrit <[email protected]> Signed-off-by: Rueian <[email protected]> Co-authored-by: Rueian <[email protected]> Signed-off-by: Rueian <[email protected]>
1 parent 0a9e664 commit bd21b27

File tree

3 files changed

+757
-0
lines changed

3 files changed

+757
-0
lines changed

cluster.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ func (c *clusterClient) Do(ctx context.Context, cmd Completed) (resp RedisResult
537537

538538
func (c *clusterClient) do(ctx context.Context, cmd Completed) (resp RedisResult) {
539539
attempts := 1
540+
redirects := 0
540541
retry:
541542
cc, err := c.pick(ctx, cmd.Slot(), c.toReplica(cmd))
542543
if err != nil {
@@ -549,6 +550,10 @@ retry:
549550
process:
550551
switch addr, mode := c.shouldRefreshRetry(resp.Error(), ctx); mode {
551552
case RedirectMove:
553+
redirects++
554+
if c.opt.ClusterOption.MaxMovedRedirections > 0 && redirects > c.opt.ClusterOption.MaxMovedRedirections {
555+
return resp
556+
}
552557
ncc := c.redirectOrNew(addr, cc, cmd.Slot(), mode)
553558
recover1:
554559
resp = ncc.Do(ctx, cmd)
@@ -557,6 +562,10 @@ process:
557562
}
558563
goto process
559564
case RedirectAsk:
565+
redirects++
566+
if c.opt.ClusterOption.MaxMovedRedirections > 0 && redirects > c.opt.ClusterOption.MaxMovedRedirections {
567+
return resp
568+
}
560569
ncc := c.redirectOrNew(addr, cc, cmd.Slot(), mode)
561570
recover2:
562571
results := ncc.DoMulti(ctx, cmds.AskingCmd, cmd)
@@ -868,6 +877,7 @@ func (c *clusterClient) DoMulti(ctx context.Context, multi ...Completed) []Redis
868877
results := resultsp.Get(len(multi), len(multi))
869878

870879
attempts := 1
880+
redirects := 0
871881

872882
retry:
873883
retries.RetryDelay = -1 // Assume no retry. Because a client retry flag can be set to false.
@@ -892,6 +902,10 @@ retry:
892902

893903
if len(retries.m) != 0 {
894904
if retries.Redirects > 0 {
905+
redirects++
906+
if c.opt.ClusterOption.MaxMovedRedirections > 0 && redirects > c.opt.ClusterOption.MaxMovedRedirections {
907+
return results.s
908+
}
895909
retries.Redirects = 0
896910
goto retry
897911
}
@@ -920,6 +934,7 @@ func fillErrs(n int, err error) (results []RedisResult) {
920934

921935
func (c *clusterClient) doCache(ctx context.Context, cmd Cacheable, ttl time.Duration) (resp RedisResult) {
922936
attempts := 1
937+
redirects := 0
923938

924939
retry:
925940
cc, err := c.pick(ctx, cmd.Slot(), c.toReplica(Completed(cmd)))
@@ -933,6 +948,10 @@ retry:
933948
process:
934949
switch addr, mode := c.shouldRefreshRetry(resp.Error(), ctx); mode {
935950
case RedirectMove:
951+
redirects++
952+
if c.opt.ClusterOption.MaxMovedRedirections > 0 && redirects > c.opt.ClusterOption.MaxMovedRedirections {
953+
return resp
954+
}
936955
ncc := c.redirectOrNew(addr, cc, cmd.Slot(), mode)
937956
recover:
938957
resp = ncc.DoCache(ctx, cmd, ttl)
@@ -941,6 +960,10 @@ process:
941960
}
942961
goto process
943962
case RedirectAsk:
963+
redirects++
964+
if c.opt.ClusterOption.MaxMovedRedirections > 0 && redirects > c.opt.ClusterOption.MaxMovedRedirections {
965+
return resp
966+
}
944967
results := c.askingMultiCache(c.redirectOrNew(addr, cc, cmd.Slot(), mode), ctx, []CacheableTTL{CT(cmd, ttl)})
945968
resp = results.s[0]
946969
resultsp.Put(results)
@@ -1235,6 +1258,7 @@ func (c *clusterClient) DoMultiCache(ctx context.Context, multi ...CacheableTTL)
12351258
results := resultsp.Get(len(multi), len(multi))
12361259

12371260
attempts := 1
1261+
redirects := 0
12381262

12391263
retry:
12401264
retries.RetryDelay = -1 // Assume no retry. Because a client retry flag can be set to false.
@@ -1259,6 +1283,10 @@ retry:
12591283

12601284
if len(retries.m) != 0 {
12611285
if retries.Redirects > 0 {
1286+
redirects++
1287+
if c.opt.ClusterOption.MaxMovedRedirections > 0 && redirects > c.opt.ClusterOption.MaxMovedRedirections {
1288+
return results.s
1289+
}
12621290
retries.Redirects = 0
12631291
goto retry
12641292
}

0 commit comments

Comments
 (0)