diff --git a/backoff.go b/backoff.go index 8a661eb..233c9a5 100644 --- a/backoff.go +++ b/backoff.go @@ -22,6 +22,16 @@ type Backoff struct { //Returns the current value of the counter and then //multiplies it Factor func (b *Backoff) Duration() time.Duration { + d := b.ForAttempt(b.attempts) + b.attempts++ + return d +} + +// ForAttempt returns the duration for a specific attempt. This is useful if +// you have a large number of independent Backoffs, but don't want use +// unnecessary memory storing the Backoff parameters per Backoff. The first +// attempt should be 0. +func (b *Backoff) ForAttempt(attempt float64) time.Duration { //Zero-values are nonsensical, so we use //them to apply defaults if b.Min == 0 { @@ -34,7 +44,7 @@ func (b *Backoff) Duration() time.Duration { b.Factor = 2 } //calculate this duration - dur := float64(b.Min) * math.Pow(b.Factor, b.attempts) + dur := float64(b.Min) * math.Pow(b.Factor, attempt) if b.Jitter == true { dur = rand.Float64()*(dur-float64(b.Min)) + float64(b.Min) } @@ -42,8 +52,6 @@ func (b *Backoff) Duration() time.Duration { if dur > float64(b.Max) { return b.Max } - //bump attempts count - b.attempts++ //return as a time.Duration return time.Duration(dur) } diff --git a/backoff_test.go b/backoff_test.go index c5fecce..d6f0359 100644 --- a/backoff_test.go +++ b/backoff_test.go @@ -20,6 +20,21 @@ func Test1(t *testing.T) { equals(t, b.Duration(), 100*time.Millisecond) } +func TestForAttempt(t *testing.T) { + + b := &Backoff{ + Min: 100 * time.Millisecond, + Max: 10 * time.Second, + Factor: 2, + } + + equals(t, b.ForAttempt(0), 100*time.Millisecond) + equals(t, b.ForAttempt(1), 200*time.Millisecond) + equals(t, b.ForAttempt(2), 400*time.Millisecond) + b.Reset() + equals(t, b.ForAttempt(0), 100*time.Millisecond) +} + func Test2(t *testing.T) { b := &Backoff{