@@ -286,8 +286,9 @@ func contextForChannel(parentCh <-chan struct{}) (context.Context, context.Cance
286
286
}
287
287
288
288
// BackoffManager manages backoff with a particular scheme based on its underlying implementation. It provides
289
- // an interface to return a timer for backoff, and caller shall backoff until Timer.C returns. If the second Backoff()
290
- // is called before the timer from the first Backoff() call finishes, the first timer will NOT be drained.
289
+ // an interface to return a timer for backoff, and caller shall backoff until Timer.C() drains. If the second Backoff()
290
+ // is called before the timer from the first Backoff() call finishes, the first timer will NOT be drained and result in
291
+ // undetermined behavior.
291
292
// The BackoffManager is supposed to be called in a single-threaded environment.
292
293
type BackoffManager interface {
293
294
Backoff () clock.Timer
@@ -317,7 +318,7 @@ func NewExponentialBackoffManager(initBackoff, maxBackoff, resetDuration time.Du
317
318
Steps : math .MaxInt32 ,
318
319
Cap : maxBackoff ,
319
320
},
320
- backoffTimer : c . NewTimer ( 0 ) ,
321
+ backoffTimer : nil ,
321
322
initialBackoff : initBackoff ,
322
323
lastBackoffStart : c .Now (),
323
324
backoffResetDuration : resetDuration ,
@@ -334,9 +335,14 @@ func (b *exponentialBackoffManagerImpl) getNextBackoff() time.Duration {
334
335
return b .backoff .Step ()
335
336
}
336
337
337
- // Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer for backoff.
338
+ // Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer for exponential backoff.
339
+ // The returned timer must be drained before calling Backoff() the second time
338
340
func (b * exponentialBackoffManagerImpl ) Backoff () clock.Timer {
339
- b .backoffTimer .Reset (b .getNextBackoff ())
341
+ if b .backoffTimer == nil {
342
+ b .backoffTimer = b .clock .NewTimer (b .getNextBackoff ())
343
+ } else {
344
+ b .backoffTimer .Reset (b .getNextBackoff ())
345
+ }
340
346
return b .backoffTimer
341
347
}
342
348
@@ -354,7 +360,7 @@ func NewJitteredBackoffManager(duration time.Duration, jitter float64, c clock.C
354
360
clock : c ,
355
361
duration : duration ,
356
362
jitter : jitter ,
357
- backoffTimer : c . NewTimer ( 0 ) ,
363
+ backoffTimer : nil ,
358
364
}
359
365
}
360
366
@@ -366,8 +372,15 @@ func (j *jitteredBackoffManagerImpl) getNextBackoff() time.Duration {
366
372
return jitteredPeriod
367
373
}
368
374
375
+ // Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer for jittered backoff.
376
+ // The returned timer must be drained before calling Backoff() the second time
369
377
func (j * jitteredBackoffManagerImpl ) Backoff () clock.Timer {
370
- j .backoffTimer .Reset (j .getNextBackoff ())
378
+ backoff := j .getNextBackoff ()
379
+ if j .backoffTimer == nil {
380
+ j .backoffTimer = j .clock .NewTimer (backoff )
381
+ } else {
382
+ j .backoffTimer .Reset (backoff )
383
+ }
371
384
return j .backoffTimer
372
385
}
373
386
0 commit comments