@@ -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,14 +516,27 @@ 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
+ recover1:
527
+ resp = ncc .Do (ctx , cmd )
528
+ if resp .Error () == errConnExpired {
529
+ goto recover1
530
+ }
521
531
goto process
522
532
case RedirectAsk :
523
- results := c .redirectOrNew (addr , cc , cmd .Slot (), mode ).DoMulti (ctx , cmds .AskingCmd , cmd )
533
+ ncc := c .redirectOrNew (addr , cc , cmd .Slot (), mode )
534
+ recover2:
535
+ results := ncc .DoMulti (ctx , cmds .AskingCmd , cmd )
524
536
resp = results .s [1 ]
537
+ if resp .Error () == errConnExpired {
538
+ goto recover2
539
+ }
525
540
resultsp .Put (results )
526
541
goto process
527
542
case RedirectRetry :
@@ -755,11 +770,38 @@ func (c *clusterClient) doretry(
755
770
clean := true
756
771
if len (re .commands ) != 0 {
757
772
resps := cc .DoMulti (ctx , re .commands ... )
773
+ if c .hasLftm {
774
+ var ml []Completed
775
+ recover:
776
+ ml = ml [:0 ]
777
+ var txIdx int // check transaction block, if zero then not in transaction
778
+ for i , resp := range resps .s {
779
+ if resp .Error () == errConnExpired {
780
+ if txIdx > 0 {
781
+ ml = re .commands [txIdx :]
782
+ } else {
783
+ ml = re .commands [i :]
784
+ }
785
+ break
786
+ }
787
+ // if no error then check if transaction block
788
+ if isMulti (re .commands [i ]) {
789
+ txIdx = i
790
+ } else if isExec (re .commands [i ]) {
791
+ txIdx = 0
792
+ }
793
+ }
794
+ if len (ml ) > 0 {
795
+ rs := cc .DoMulti (ctx , ml ... ).s
796
+ resps .s = append (resps .s [:len (resps .s )- len (rs )], rs ... )
797
+ goto recover
798
+ }
799
+ }
758
800
clean = c .doresultfn (ctx , results , retries , mu , cc , re .cIndexes , re .commands , resps .s , attempts , hasInit )
759
801
resultsp .Put (resps )
760
802
}
761
803
if len (re .cAskings ) != 0 {
762
- resps := askingMulti (cc , ctx , re .cAskings )
804
+ resps := c . askingMulti (cc , ctx , re .cAskings )
763
805
clean = c .doresultfn (ctx , results , retries , mu , cc , re .aIndexes , re .cAskings , resps .s , attempts , hasInit ) && clean
764
806
resultsp .Put (resps )
765
807
}
@@ -845,13 +887,21 @@ retry:
845
887
return newErrResult (err )
846
888
}
847
889
resp = cc .DoCache (ctx , cmd , ttl )
890
+ if resp .Error () == errConnExpired {
891
+ goto retry
892
+ }
848
893
process:
849
894
switch addr , mode := c .shouldRefreshRetry (resp .Error (), ctx ); mode {
850
895
case RedirectMove :
851
- resp = c .redirectOrNew (addr , cc , cmd .Slot (), mode ).DoCache (ctx , cmd , ttl )
896
+ ncc := c .redirectOrNew (addr , cc , cmd .Slot (), mode )
897
+ recover:
898
+ resp = ncc .DoCache (ctx , cmd , ttl )
899
+ if resp .Error () == errConnExpired {
900
+ goto recover
901
+ }
852
902
goto process
853
903
case RedirectAsk :
854
- results := askingMultiCache (c .redirectOrNew (addr , cc , cmd .Slot (), mode ), ctx , []CacheableTTL {CT (cmd , ttl )})
904
+ results := c . askingMultiCache (c .redirectOrNew (addr , cc , cmd .Slot (), mode ), ctx , []CacheableTTL {CT (cmd , ttl )})
855
905
resp = results .s [0 ]
856
906
resultsp .Put (results )
857
907
goto process
@@ -875,7 +925,7 @@ func (c *clusterClient) DoCache(ctx context.Context, cmd Cacheable, ttl time.Dur
875
925
return resp
876
926
}
877
927
878
- func askingMulti (cc conn , ctx context.Context , multi []Completed ) * redisresults {
928
+ func ( c * clusterClient ) askingMulti (cc conn , ctx context.Context , multi []Completed ) * redisresults {
879
929
var inTx bool
880
930
commands := make ([]Completed , 0 , len (multi )* 2 )
881
931
for _ , cmd := range multi {
@@ -889,6 +939,26 @@ func askingMulti(cc conn, ctx context.Context, multi []Completed) *redisresults
889
939
}
890
940
results := resultsp .Get (0 , len (multi ))
891
941
resps := cc .DoMulti (ctx , commands ... )
942
+ if c .hasLftm {
943
+ var ml []Completed
944
+ recover:
945
+ ml = ml [:0 ]
946
+ var askingIdx int
947
+ for i , resp := range resps .s {
948
+ if commands [i ] == cmds .AskingCmd {
949
+ askingIdx = i
950
+ }
951
+ if resp .Error () == errConnExpired {
952
+ ml = commands [askingIdx :]
953
+ break
954
+ }
955
+ }
956
+ if len (ml ) > 0 {
957
+ rs := cc .DoMulti (ctx , ml ... ).s
958
+ resps .s = append (resps .s [:len (resps .s )- len (rs )], rs ... )
959
+ goto recover
960
+ }
961
+ }
892
962
for i , resp := range resps .s {
893
963
if commands [i ] != cmds .AskingCmd {
894
964
results .s = append (results .s , resp )
@@ -898,14 +968,30 @@ func askingMulti(cc conn, ctx context.Context, multi []Completed) *redisresults
898
968
return results
899
969
}
900
970
901
- func askingMultiCache (cc conn , ctx context.Context , multi []CacheableTTL ) * redisresults {
971
+ func ( c * clusterClient ) askingMultiCache (cc conn , ctx context.Context , multi []CacheableTTL ) * redisresults {
902
972
commands := make ([]Completed , 0 , len (multi )* 6 )
903
973
for _ , cmd := range multi {
904
974
ck , _ := cmds .CacheKey (cmd .Cmd )
905
975
commands = append (commands , cc .OptInCmd (), cmds .AskingCmd , cmds .MultiCmd , cmds .NewCompleted ([]string {"PTTL" , ck }), Completed (cmd .Cmd ), cmds .ExecCmd )
906
976
}
907
977
results := resultsp .Get (0 , len (multi ))
908
978
resps := cc .DoMulti (ctx , commands ... )
979
+ if c .hasLftm {
980
+ var ml []Completed
981
+ recover:
982
+ ml = ml [:0 ]
983
+ for i := 5 ; i < len (resps .s ); i += 6 { // check exec command error only
984
+ if resps .s [i ].Error () == errConnExpired {
985
+ ml = commands [i - 5 :]
986
+ break
987
+ }
988
+ }
989
+ if len (ml ) > 0 {
990
+ rs := cc .DoMulti (ctx , ml ... ).s
991
+ resps .s = append (resps .s [:len (resps .s )- len (rs )], rs ... )
992
+ goto recover
993
+ }
994
+ }
909
995
for i := 5 ; i < len (resps .s ); i += 6 {
910
996
if arr , err := resps .s [i ].ToArray (); err != nil {
911
997
if preErr := resps .s [i - 1 ].Error (); preErr != nil { // if {Cmd} get a RedisError
@@ -1049,11 +1135,27 @@ func (c *clusterClient) doretrycache(
1049
1135
clean := true
1050
1136
if len (re .commands ) != 0 {
1051
1137
resps := cc .DoMultiCache (ctx , re .commands ... )
1138
+ if c .hasLftm {
1139
+ var ml []CacheableTTL
1140
+ recover:
1141
+ ml = ml [:0 ]
1142
+ for i , resp := range resps .s {
1143
+ if resp .Error () == errConnExpired {
1144
+ ml = re .commands [i :]
1145
+ break
1146
+ }
1147
+ }
1148
+ if len (ml ) > 0 {
1149
+ rs := cc .DoMultiCache (ctx , ml ... ).s
1150
+ resps .s = append (resps .s [:len (resps .s )- len (rs )], rs ... )
1151
+ goto recover
1152
+ }
1153
+ }
1052
1154
clean = c .resultcachefn (ctx , results , retries , mu , cc , re .cIndexes , re .commands , resps .s , attempts )
1053
1155
resultsp .Put (resps )
1054
1156
}
1055
1157
if len (re .cAskings ) != 0 {
1056
- resps := askingMultiCache (cc , ctx , re .cAskings )
1158
+ resps := c . askingMultiCache (cc , ctx , re .cAskings )
1057
1159
clean = c .resultcachefn (ctx , results , retries , mu , cc , re .aIndexes , re .cAskings , resps .s , attempts ) && clean
1058
1160
resultsp .Put (resps )
1059
1161
}
@@ -1130,6 +1232,9 @@ retry:
1130
1232
goto ret
1131
1233
}
1132
1234
err = cc .Receive (ctx , subscribe , fn )
1235
+ if err == errConnExpired {
1236
+ goto retry
1237
+ }
1133
1238
if _ , mode := c .shouldRefreshRetry (err , ctx ); c .retry && mode != RedirectNone {
1134
1239
shouldRetry := c .retryHandler .WaitOrSkipRetry (ctx , attempts , subscribe , err )
1135
1240
if shouldRetry {
0 commit comments