Skip to content

Commit

Permalink
make exponentional backoff thread safe
Browse files Browse the repository at this point in the history
  • Loading branch information
stephnr committed Oct 7, 2018
1 parent 62661b4 commit 4036378
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
57 changes: 57 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package backoff

import (
"context"
"errors"
"log"
"sync"
"time"
)

func ExampleRetry() {
Expand Down Expand Up @@ -40,6 +43,60 @@ func ExampleRetryContext() {
// Operation is successful.
}

func ExampleThreadSafe() {
backoff := NewExponentialBackOff()

backoff.MaxElapsedTime = time.Millisecond * 500
backoff.MaxInterval = time.Millisecond * 200

wg := sync.WaitGroup{}
wg.Add(2)

failTimes := 3

go func() {
tries := 0

err := Retry(func() error {
if tries >= failTimes {
return nil
}

tries++
return errors.New("FAILED")
}, backoff)

if err != nil {
// Handle error.
}

// Operation is successful.
wg.Done()
}()

go func() {
tries := 0

err := Retry(func() error {
if tries >= failTimes {
return nil
}

tries++
return errors.New("FAILED")
}, backoff)

if err != nil {
// Handle error.
}

// Operation is successful.
wg.Done()
}()

wg.Wait()
}

func ExampleTicker() {
// An operation that may fail.
operation := func() error {
Expand Down
9 changes: 9 additions & 0 deletions exponential.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package backoff

import (
"math/rand"
"sync"
"time"
)

Expand Down Expand Up @@ -63,6 +64,7 @@ type ExponentialBackOff struct {

currentInterval time.Duration
startTime time.Time
mutex *sync.Mutex
}

// Clock is an interface that returns current time for BackOff.
Expand All @@ -88,6 +90,7 @@ func NewExponentialBackOff() *ExponentialBackOff {
MaxInterval: DefaultMaxInterval,
MaxElapsedTime: DefaultMaxElapsedTime,
Clock: SystemClock,
mutex: &sync.Mutex{},
}
b.Reset()
return b
Expand All @@ -104,13 +107,19 @@ var SystemClock = systemClock{}

// Reset the interval back to the initial retry interval and restarts the timer.
func (b *ExponentialBackOff) Reset() {
b.mutex.Lock()
defer b.mutex.Unlock()

b.currentInterval = b.InitialInterval
b.startTime = b.Clock.Now()
}

// NextBackOff calculates the next backoff interval using the formula:
// Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval)
func (b *ExponentialBackOff) NextBackOff() time.Duration {
b.mutex.Lock()
defer b.mutex.Unlock()

// Make sure we have not gone over the maximum elapsed time.
if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
return Stop
Expand Down

0 comments on commit 4036378

Please sign in to comment.