Skip to content

Commit

Permalink
client/v3: Add backoff before retry when watch stream returns unavail…
Browse files Browse the repository at this point in the history
…able

The client retries connection without backoff when the server is gone
after the watch stream is established. This results in high CPU usage
in the client process. This change introduces backoff when the stream is
failed and unavailable.

Signed-off-by: Hisanobu Tomari <[email protected]>
  • Loading branch information
tomari committed Oct 7, 2022
1 parent 6a0bbf3 commit 428fb96
Showing 1 changed file with 18 additions and 11 deletions.
29 changes: 18 additions & 11 deletions client/v3/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ func (w *watchGrpcStream) run() {
cancelSet := make(map[int64]struct{})

var cur *pb.WatchResponse
backoff := time.Millisecond
for {
select {
// Watch() requested
Expand Down Expand Up @@ -676,6 +677,7 @@ func (w *watchGrpcStream) run() {
closeErr = err
return
}
backoff = w.backoffIfUnavailable(backoff, err)
if wc, closeErr = w.newWatchClient(); closeErr != nil {
return
}
Expand Down Expand Up @@ -995,6 +997,21 @@ func (w *watchGrpcStream) joinSubstreams() {

var maxBackoff = 100 * time.Millisecond

func (w *watchGrpcStream) backoffIfUnavailable(backoff time.Duration, err error) time.Duration {
if isUnavailableErr(w.ctx, err) {
// retry, but backoff
if backoff < maxBackoff {
// 25% backoff factor
backoff = backoff + backoff/4
if backoff > maxBackoff {
backoff = maxBackoff
}
}
time.Sleep(backoff)
}
return backoff
}

// openWatchClient retries opening a watch client until success or halt.
// manually retry in case "ws==nil && err==nil"
// TODO: remove FailFast=false
Expand All @@ -1015,17 +1032,7 @@ func (w *watchGrpcStream) openWatchClient() (ws pb.Watch_WatchClient, err error)
if isHaltErr(w.ctx, err) {
return nil, v3rpc.Error(err)
}
if isUnavailableErr(w.ctx, err) {
// retry, but backoff
if backoff < maxBackoff {
// 25% backoff factor
backoff = backoff + backoff/4
if backoff > maxBackoff {
backoff = maxBackoff
}
}
time.Sleep(backoff)
}
backoff = w.backoffIfUnavailable(backoff, err)
}
return ws, nil
}
Expand Down

0 comments on commit 428fb96

Please sign in to comment.