go-backoff
Backoff algorithm and helpers for Go
SYNOPSIS
import "github.com/lestrrat-go/backoff"
func Func(arg Foo) (Result, error) { ... }
var policy = backoff.NewExponential(
backoff.WithInterval(500*time.Millisecond), // base interval
backoff.WithJitterFactor(0.05), // 5% jitter
backoff.WithMaxRetries(25), // If not specified, default number of retries is 10
)
func RetryFunc(arg Foo) (Result, error) {
b, cancel := policy.Start(context.Background())
defer cancel()
for backoff.Continue(b) {
res, err := Func(arg)
if err == nil {
return res, nil
}
}
return nil, errors.New(`tried very hard, but no luck`)
}
Simple Usage
func ExampleRetry() {
count := 0
e := backoff.ExecuteFunc(func(_ context.Context) error {
// This is a silly example that succeeds on every 10th try
count++
if count%10 == 0 {
return nil
}
return errors.New(`dummy`)
})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Note that the following will only retry up to 10 attempts,
// as it's the default. If you want to wait retry forever, use
// backoff.WithRetryForever (or `backoff.WithMaxRetries(0)`)
p := backoff.NewExponential()
if err := backoff.Retry(ctx, p, e); err != nil {
log.Printf("failed to call function after repeated tries")
}
}
DESCRIPTION
This library is an implementation of backoff algorithm for retrying operations
in an idiomatic Go way. It respects context.Context
natively, and the critical
notifications are done through channel operations, allowing you to write code
that is both more explicit and flexibile.
It also exports a utility function Retry
, for simple operations.
For a longer discussion, please read this article
CONSTRUCTOR OPTIONS
WithFactor
TODO
WithInterval
TODO
WithJitterFactor
TODO
WithMaxInterval
WithMaxInterval specifies the maximum interval between retries, and is currently only applicable to exponential backoffs.
By default this is capped at 2 minutes. If you would like to change this value, you must explicitly specify it through this option.
If a value of 0 is specified, then there is no limit, and the backoff interval will keep increasing.
WithMaxRetries
WithMaxRetries specifies the maximum number of attempts that can be made by the backoff policies. By default each policy tries up to 10 times.
If you would like to retry forever, specify "0" and pass to the constructor of each policy.
WithRetryForever
WithRetryForever is a short-hand for WithMaxRetries(0)
-- well, ok, it's not
a short-hand. But it makes reading the code just a tiny bit easier
WithMaxElapsedTime
WithMaxElapsedTime specifies the maximum amount of accumulative time that the backoff is allowed to wait before it is considered failed.
TODO
- Refine the timeouts generated by exponential backoff algorithm (help wanted!)
PRIOR ARTS
github.com/cenkalti/backoff
This library is featureful, but one thing that gets to me is the fact that it essentially forces you to create a closure over the operation to be retried.
github.com/jpillora/backoff
This library is a very simple implementation of calculating backoff durations. I wanted it to let me know when to stop too, so it was missing a few things.
DUMB BENCHMARK
make benchmark
go test -run=none -tags bench -bench . -benchmem -benchtime 20s
goos: darwin
goarch: amd64
pkg: github.com/lestrrat-go/backoff
Benchmark/cenkalti-4 3 6828914804 ns/op 1205 B/op 24 allocs/op
Benchmark/lestrrat-4 5 4842358461 ns/op 1022 B/op 20 allocs/op
PASS
ok github.com/lestrrat-go/backoff 70.711s