Skip to content

Commit 410d28c

Browse files
authored
Merge pull request #9840 from liggitt/client-hotloop
Backoff on reestablishing watches when Unavailable errors are encountered
2 parents 03cec4a + d1579c9 commit 410d28c

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

Diff for: clientv3/client.go

+14
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,20 @@ func isHaltErr(ctx context.Context, err error) bool {
527527
return ev.Code() != codes.Unavailable && ev.Code() != codes.Internal
528528
}
529529

530+
// isUnavailableErr returns true if the given error is an unavailable error
531+
func isUnavailableErr(ctx context.Context, err error) bool {
532+
if ctx != nil && ctx.Err() != nil {
533+
return false
534+
}
535+
if err == nil {
536+
return false
537+
}
538+
ev, _ := status.FromError(err)
539+
// Unavailable codes mean the system will be right back.
540+
// (e.g., can't connect, lost leader)
541+
return ev.Code() == codes.Unavailable
542+
}
543+
530544
func toErr(ctx context.Context, err error) error {
531545
if err == nil {
532546
return nil

Diff for: clientv3/watch.go

+14
Original file line numberDiff line numberDiff line change
@@ -830,10 +830,13 @@ func (w *watchGrpcStream) joinSubstreams() {
830830
}
831831
}
832832

833+
var maxBackoff = 100 * time.Millisecond
834+
833835
// openWatchClient retries opening a watch client until success or halt.
834836
// manually retry in case "ws==nil && err==nil"
835837
// TODO: remove FailFast=false
836838
func (w *watchGrpcStream) openWatchClient() (ws pb.Watch_WatchClient, err error) {
839+
backoff := time.Millisecond
837840
for {
838841
select {
839842
case <-w.ctx.Done():
@@ -849,6 +852,17 @@ func (w *watchGrpcStream) openWatchClient() (ws pb.Watch_WatchClient, err error)
849852
if isHaltErr(w.ctx, err) {
850853
return nil, v3rpc.Error(err)
851854
}
855+
if isUnavailableErr(w.ctx, err) {
856+
// retry, but backoff
857+
if backoff < maxBackoff {
858+
// 25% backoff factor
859+
backoff = backoff + backoff/4
860+
if backoff > maxBackoff {
861+
backoff = maxBackoff
862+
}
863+
}
864+
time.Sleep(backoff)
865+
}
852866
}
853867
return ws, nil
854868
}

0 commit comments

Comments
 (0)