1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package backoff
import (
"fmt"
"time"
)
// Operation represents an operation that will be retried
// based on some backoff strategy if it fails.
type Operation func() error
// ErrFailedPermanently is an error raised by Do when the
// underlying Operation has been retried maxAttempts times.
type ErrFailedPermanently struct {
attempts int
LastErr error
}
func (e *ErrFailedPermanently) Error() string {
return fmt.Sprintf("operation failed permanently after %d attempts: %v", e.attempts, e.LastErr)
}
// Do performs the provided Operation up to maxAttempts times
// with delays in between each retry according to the provided
// Strategy.
func Do(maxAttempts int, strategy Strategy, op Operation) error {
var attempt int
for {
attempt++
err := op()
if err == nil {
return nil
}
if attempt == maxAttempts {
return &ErrFailedPermanently{
attempts: maxAttempts,
LastErr: err,
}
}
time.Sleep(strategy.Duration(attempt - 1))
}
}