mirror of https://github.com/libp2p/go-libp2p.git
Marco Munizaga
3 weeks ago
committed by
GitHub
3 changed files with 132 additions and 4 deletions
@ -0,0 +1,52 @@ |
|||
package backoff |
|||
|
|||
import ( |
|||
"time" |
|||
) |
|||
|
|||
var since = time.Since |
|||
|
|||
const defaultDelay = 100 * time.Millisecond |
|||
const defaultMaxDelay = 1 * time.Minute |
|||
|
|||
type ExpBackoff struct { |
|||
Delay time.Duration |
|||
MaxDelay time.Duration |
|||
|
|||
failures int |
|||
lastRun time.Time |
|||
} |
|||
|
|||
func (b *ExpBackoff) init() { |
|||
if b.Delay == 0 { |
|||
b.Delay = defaultDelay |
|||
} |
|||
if b.MaxDelay == 0 { |
|||
b.MaxDelay = defaultMaxDelay |
|||
} |
|||
} |
|||
|
|||
func (b *ExpBackoff) calcDelay() time.Duration { |
|||
delay := b.Delay * time.Duration(1<<(b.failures-1)) |
|||
delay = min(delay, b.MaxDelay) |
|||
return delay |
|||
} |
|||
|
|||
func (b *ExpBackoff) Run(f func() error) (err error, ran bool) { |
|||
b.init() |
|||
|
|||
if b.failures != 0 { |
|||
if since(b.lastRun) < b.calcDelay() { |
|||
return nil, false |
|||
} |
|||
} |
|||
|
|||
b.lastRun = time.Now() |
|||
err = f() |
|||
if err == nil { |
|||
b.failures = 0 |
|||
} else { |
|||
b.failures++ |
|||
} |
|||
return err, true |
|||
} |
@ -0,0 +1,59 @@ |
|||
package backoff |
|||
|
|||
import ( |
|||
"errors" |
|||
"testing" |
|||
"time" |
|||
|
|||
"github.com/stretchr/testify/require" |
|||
) |
|||
|
|||
func TestBackoff(t *testing.T) { |
|||
origSince := since |
|||
defer func() { since = origSince }() |
|||
|
|||
var timeSince time.Duration |
|||
since = func(time.Time) time.Duration { |
|||
return timeSince |
|||
} |
|||
|
|||
var maybeErr error |
|||
b := &ExpBackoff{} |
|||
f := func() error { return maybeErr } |
|||
|
|||
err, ran := b.Run(f) |
|||
require.True(t, ran) |
|||
require.NoError(t, err) |
|||
|
|||
maybeErr = errors.New("some error") |
|||
err, ran = b.Run(f) |
|||
require.True(t, ran) |
|||
require.Error(t, err) |
|||
|
|||
// Rerun again
|
|||
_, ran = b.Run(f) |
|||
require.False(t, ran) |
|||
|
|||
timeSince = 100*time.Millisecond + 1 |
|||
err, ran = b.Run(f) |
|||
require.True(t, ran) |
|||
require.Error(t, err) |
|||
|
|||
timeSince = 100*time.Millisecond + 1 |
|||
_, ran = b.Run(f) |
|||
require.False(t, ran) |
|||
|
|||
timeSince = 200*time.Millisecond + 1 |
|||
err, ran = b.Run(f) |
|||
require.True(t, ran) |
|||
require.Error(t, err) |
|||
|
|||
for timeSince < defaultMaxDelay*4 { |
|||
timeSince *= 2 |
|||
err, ran = b.Run(f) |
|||
require.True(t, ran) |
|||
require.Error(t, err) |
|||
} |
|||
|
|||
require.Equal(t, defaultMaxDelay, b.calcDelay()) |
|||
} |
Loading…
Reference in new issue