@ -15,8 +15,14 @@ const MAX_BACKOFF_MSEC = 30000
type Backoff struct {
type Backoff struct {
n int
n int
// Name is the name of this backoff timer, for logging purposes.
Name string
Name string
// NewTimer is the function that acts like time.NewTimer().
// You can override this in unit tests.
NewTimer func ( d time . Duration ) * time . Timer
NewTimer func ( d time . Duration ) * time . Timer
// LogLongerThan sets the minimum time of a single backoff interval
// before we mention it in the log.
LogLongerThan time . Duration
}
}
func ( b * Backoff ) BackOff ( ctx context . Context , err error ) {
func ( b * Backoff ) BackOff ( ctx context . Context , err error ) {
@ -31,14 +37,15 @@ func (b *Backoff) BackOff(ctx context.Context, err error) {
// Randomize the delay between 0.5-1.5 x msec, in order
// Randomize the delay between 0.5-1.5 x msec, in order
// to prevent accidental "thundering herd" problems.
// to prevent accidental "thundering herd" problems.
msec = rand . Intn ( msec ) + msec / 2
msec = rand . Intn ( msec ) + msec / 2
if msec >= 2000 {
dur := time . Duration ( msec ) * time . Millisecond
if dur >= b . LogLongerThan {
log . Printf ( "%s: backoff: %d msec\n" , b . Name , msec )
log . Printf ( "%s: backoff: %d msec\n" , b . Name , msec )
}
}
newTimer := b . NewTimer
newTimer := b . NewTimer
if newTimer == nil {
if newTimer == nil {
newTimer = time . NewTimer
newTimer = time . NewTimer
}
}
t := newTimer ( time. Duration ( msec ) * time . Millisecond )
t := newTimer ( dur )
select {
select {
case <- ctx . Done ( ) :
case <- ctx . Done ( ) :
t . Stop ( )
t . Stop ( )