-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Justification for jitter and growth factor: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/. Add backoff to the Consul instancer loop. Fixes #627.
- Loading branch information
Nico Tonozzi
committed
Dec 3, 2017
1 parent
53f10af
commit 924501a
Showing
4 changed files
with
113 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package backoff | ||
|
||
import ( | ||
"math/rand" | ||
"sync/atomic" | ||
"time" | ||
) | ||
|
||
const ( | ||
DefaultInterval = time.Second | ||
DefaultMaxInterval = time.Minute | ||
) | ||
|
||
// ExponentialBackoff provides jittered exponential durations for the purpose of | ||
// avoiding flodding a service with requests. | ||
type ExponentialBackoff struct { | ||
Interval time.Duration | ||
Max time.Duration | ||
|
||
currentInterval atomic.Value | ||
cancel <-chan struct{} | ||
} | ||
|
||
// New creates a new ExpontentialBackoff instance with the default values, and | ||
// an optional cancel channel. | ||
func New(cancel <-chan struct{}) *ExponentialBackoff { | ||
backoff := ExponentialBackoff{ | ||
Interval: DefaultInterval, | ||
Max: DefaultMaxInterval, | ||
cancel: cancel, | ||
} | ||
backoff.Reset() | ||
return &backoff | ||
} | ||
|
||
// Reset should be called after a request succeeds. | ||
func (b *ExponentialBackoff) Reset() { | ||
b.currentInterval.Store(b.Interval) | ||
} | ||
|
||
// Wait increases the backoff and blocks until the duration is over or the | ||
// cancel channel is filled. | ||
func (b *ExponentialBackoff) Wait() { | ||
d := b.NextBackoff() | ||
select { | ||
case <-time.After(d): | ||
case <-b.cancel: | ||
} | ||
} | ||
|
||
// NextBackoff updates the time interval and returns the updated value. | ||
func (b *ExponentialBackoff) NextBackoff() time.Duration { | ||
d := b.next() | ||
if d > b.Max { | ||
d = b.Max | ||
} | ||
|
||
b.currentInterval.Store(d) | ||
return d | ||
} | ||
|
||
// next provides the exponential jittered backoff value. See | ||
// https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ | ||
// for rationale. | ||
func (b *ExponentialBackoff) next() time.Duration { | ||
current := b.currentInterval.Load().(time.Duration) | ||
d := float64(current * 2) | ||
jitter := rand.Float64() + 0.5 | ||
return time.Duration(d * jitter) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package backoff | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestNext(t *testing.T) { | ||
b := ExponentialBackoff{} | ||
b.currentInterval.Store(time.Duration(12)) | ||
|
||
next := b.next() | ||
|
||
if next < 12 || next > 36 { | ||
t.Errorf("Expected next to be between 12 and 36, got %d", 12) | ||
} | ||
} | ||
|
||
func TestNextBackoffMax(t *testing.T) { | ||
max := time.Duration(13) | ||
b := ExponentialBackoff{ | ||
Max: max, | ||
} | ||
b.currentInterval.Store(time.Duration(14)) | ||
next := b.NextBackoff() | ||
if next != max { | ||
t.Errorf("Expected next to be max, %d, but got %d", max, next) | ||
} | ||
|
||
current := b.currentInterval.Load().(time.Duration) | ||
if current != max { | ||
t.Errorf("Expected currentInterval to be max, %d, but got %d", max, current) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters