@@ -35,6 +35,7 @@ type clusterClient struct {
35
35
stop uint32
36
36
cmd Builder
37
37
retry bool
38
+ hasLftm bool
38
39
}
39
40
40
41
// NOTE: connrole and conn must be initialized at the same time
@@ -57,6 +58,7 @@ func newClusterClient(opt *ClientOption, connFn connFn, retryer retryHandler) (*
57
58
retry : ! opt .DisableRetry ,
58
59
retryHandler : retryer ,
59
60
stopCh : make (chan struct {}),
61
+ hasLftm : opt .ConnLifetime > 0 ,
60
62
}
61
63
62
64
if opt .ReplicaOnly && opt .SendToReplicas != nil {
@@ -514,13 +516,21 @@ retry:
514
516
return newErrResult (err )
515
517
}
516
518
resp = cc .Do (ctx , cmd )
519
+ if resp .Error () == errConnExpired {
520
+ goto retry
521
+ }
517
522
process:
518
523
switch addr , mode := c .shouldRefreshRetry (resp .Error (), ctx ); mode {
519
524
case RedirectMove :
520
- resp = c .redirectOrNew (addr , cc , cmd .Slot (), mode ).Do (ctx , cmd )
525
+ ncc := c .redirectOrNew (addr , cc , cmd .Slot (), mode )
526
+ resp = ncc .Do (ctx , cmd )
527
+ if resp .Error () == errConnExpired {
528
+ goto retry
529
+ }
521
530
goto process
522
531
case RedirectAsk :
523
- results := c .redirectOrNew (addr , cc , cmd .Slot (), mode ).DoMulti (ctx , cmds .AskingCmd , cmd )
532
+ ncc := c .redirectOrNew (addr , cc , cmd .Slot (), mode )
533
+ results := c .doMulti (ctx , ncc , cmds .AskingCmd , cmd )
524
534
resp = results .s [1 ]
525
535
resultsp .Put (results )
526
536
goto process
@@ -754,12 +764,12 @@ func (c *clusterClient) doretry(
754
764
) {
755
765
clean := true
756
766
if len (re .commands ) != 0 {
757
- resps := cc . DoMulti (ctx , re .commands ... )
767
+ resps := c . doMulti (ctx , cc , re .commands ... )
758
768
clean = c .doresultfn (ctx , results , retries , mu , cc , re .cIndexes , re .commands , resps .s , attempts , hasInit )
759
769
resultsp .Put (resps )
760
770
}
761
771
if len (re .cAskings ) != 0 {
762
- resps := askingMulti (cc , ctx , re .cAskings )
772
+ resps := c . askingMulti (cc , ctx , re .cAskings )
763
773
clean = c .doresultfn (ctx , results , retries , mu , cc , re .aIndexes , re .cAskings , resps .s , attempts , hasInit ) && clean
764
774
resultsp .Put (resps )
765
775
}
@@ -845,13 +855,19 @@ retry:
845
855
return newErrResult (err )
846
856
}
847
857
resp = cc .DoCache (ctx , cmd , ttl )
858
+ if resp .Error () == errConnExpired {
859
+ goto retry
860
+ }
848
861
process:
849
862
switch addr , mode := c .shouldRefreshRetry (resp .Error (), ctx ); mode {
850
863
case RedirectMove :
851
864
resp = c .redirectOrNew (addr , cc , cmd .Slot (), mode ).DoCache (ctx , cmd , ttl )
865
+ if resp .Error () == errConnExpired {
866
+ goto retry
867
+ }
852
868
goto process
853
869
case RedirectAsk :
854
- results := askingMultiCache (c .redirectOrNew (addr , cc , cmd .Slot (), mode ), ctx , []CacheableTTL {CT (cmd , ttl )})
870
+ results := c . askingMultiCache (c .redirectOrNew (addr , cc , cmd .Slot (), mode ), ctx , []CacheableTTL {CT (cmd , ttl )})
855
871
resp = results .s [0 ]
856
872
resultsp .Put (results )
857
873
goto process
@@ -875,7 +891,49 @@ func (c *clusterClient) DoCache(ctx context.Context, cmd Cacheable, ttl time.Dur
875
891
return resp
876
892
}
877
893
878
- func askingMulti (cc conn , ctx context.Context , multi []Completed ) * redisresults {
894
+ func (c * clusterClient ) doMulti (ctx context.Context , cc conn , multi ... Completed ) * redisresults {
895
+ resps := cc .DoMulti (ctx , multi ... )
896
+ if c .hasLftm {
897
+ var ml []Completed
898
+ recover:
899
+ ml = ml [:0 ]
900
+ for i , resp := range resps .s {
901
+ if resp .Error () == errConnExpired {
902
+ ml = multi [i :]
903
+ break
904
+ }
905
+ }
906
+ if len (ml ) > 0 {
907
+ rs := cc .DoMulti (ctx , ml ... ).s
908
+ resps .s = append (resps .s [:len (resps .s )- len (rs )], rs ... )
909
+ goto recover
910
+ }
911
+ }
912
+ return resps
913
+ }
914
+
915
+ func (c * clusterClient ) doMultiCache (ctx context.Context , cc conn , multi ... CacheableTTL ) * redisresults {
916
+ resps := cc .DoMultiCache (ctx , multi ... )
917
+ if c .hasLftm {
918
+ var ml []CacheableTTL
919
+ recover:
920
+ ml = ml [:0 ]
921
+ for i , resp := range resps .s {
922
+ if resp .Error () == errConnExpired {
923
+ ml = multi [i :]
924
+ break
925
+ }
926
+ }
927
+ if len (ml ) > 0 {
928
+ rs := cc .DoMultiCache (ctx , ml ... ).s
929
+ resps .s = append (resps .s [:len (resps .s )- len (rs )], rs ... )
930
+ goto recover
931
+ }
932
+ }
933
+ return resps
934
+ }
935
+
936
+ func (c * clusterClient ) askingMulti (cc conn , ctx context.Context , multi []Completed ) * redisresults {
879
937
var inTx bool
880
938
commands := make ([]Completed , 0 , len (multi )* 2 )
881
939
for _ , cmd := range multi {
@@ -888,7 +946,7 @@ func askingMulti(cc conn, ctx context.Context, multi []Completed) *redisresults
888
946
}
889
947
}
890
948
results := resultsp .Get (0 , len (multi ))
891
- resps := cc . DoMulti (ctx , commands ... )
949
+ resps := c . doMulti (ctx , cc , commands ... )
892
950
for i , resp := range resps .s {
893
951
if commands [i ] != cmds .AskingCmd {
894
952
results .s = append (results .s , resp )
@@ -898,14 +956,14 @@ func askingMulti(cc conn, ctx context.Context, multi []Completed) *redisresults
898
956
return results
899
957
}
900
958
901
- func askingMultiCache (cc conn , ctx context.Context , multi []CacheableTTL ) * redisresults {
959
+ func ( c * clusterClient ) askingMultiCache (cc conn , ctx context.Context , multi []CacheableTTL ) * redisresults {
902
960
commands := make ([]Completed , 0 , len (multi )* 6 )
903
961
for _ , cmd := range multi {
904
962
ck , _ := cmds .CacheKey (cmd .Cmd )
905
963
commands = append (commands , cc .OptInCmd (), cmds .AskingCmd , cmds .MultiCmd , cmds .NewCompleted ([]string {"PTTL" , ck }), Completed (cmd .Cmd ), cmds .ExecCmd )
906
964
}
907
965
results := resultsp .Get (0 , len (multi ))
908
- resps := cc . DoMulti (ctx , commands ... )
966
+ resps := c . doMulti (ctx , cc , commands ... )
909
967
for i := 5 ; i < len (resps .s ); i += 6 {
910
968
if arr , err := resps .s [i ].ToArray (); err != nil {
911
969
if preErr := resps .s [i - 1 ].Error (); preErr != nil { // if {Cmd} get a RedisError
@@ -1048,12 +1106,12 @@ func (c *clusterClient) doretrycache(
1048
1106
) {
1049
1107
clean := true
1050
1108
if len (re .commands ) != 0 {
1051
- resps := cc . DoMultiCache (ctx , re .commands ... )
1109
+ resps := c . doMultiCache (ctx , cc , re .commands ... )
1052
1110
clean = c .resultcachefn (ctx , results , retries , mu , cc , re .cIndexes , re .commands , resps .s , attempts )
1053
1111
resultsp .Put (resps )
1054
1112
}
1055
1113
if len (re .cAskings ) != 0 {
1056
- resps := askingMultiCache (cc , ctx , re .cAskings )
1114
+ resps := c . askingMultiCache (cc , ctx , re .cAskings )
1057
1115
clean = c .resultcachefn (ctx , results , retries , mu , cc , re .aIndexes , re .cAskings , resps .s , attempts ) && clean
1058
1116
resultsp .Put (resps )
1059
1117
}
@@ -1130,6 +1188,9 @@ retry:
1130
1188
goto ret
1131
1189
}
1132
1190
err = cc .Receive (ctx , subscribe , fn )
1191
+ if err == errConnExpired {
1192
+ goto retry
1193
+ }
1133
1194
if _ , mode := c .shouldRefreshRetry (err , ctx ); c .retry && mode != RedirectNone {
1134
1195
shouldRetry := c .retryHandler .WaitOrSkipRetry (ctx , attempts , subscribe , err )
1135
1196
if shouldRetry {
0 commit comments