...
1
16
17
18
19 package exponentialbackoff
20
21 import (
22 "fmt"
23 "time"
24 )
25
26 const (
27
28
29
30
31 initialDurationBeforeRetry = 500 * time.Millisecond
32
33
34
35
36
37 maxDurationBeforeRetry = 2*time.Minute + 2*time.Second
38 )
39
40
41
42 type ExponentialBackoff struct {
43 lastError error
44 lastErrorTime time.Time
45 durationBeforeRetry time.Duration
46 }
47
48
49
50 func (expBackoff *ExponentialBackoff) SafeToRetry(operationName string) error {
51 if time.Since(expBackoff.lastErrorTime) <= expBackoff.durationBeforeRetry {
52 return NewExponentialBackoffError(operationName, *expBackoff)
53 }
54
55 return nil
56 }
57
58 func (expBackoff *ExponentialBackoff) Update(err *error) {
59 if expBackoff.durationBeforeRetry == 0 {
60 expBackoff.durationBeforeRetry = initialDurationBeforeRetry
61 } else {
62 expBackoff.durationBeforeRetry = 2 * expBackoff.durationBeforeRetry
63 if expBackoff.durationBeforeRetry > maxDurationBeforeRetry {
64 expBackoff.durationBeforeRetry = maxDurationBeforeRetry
65 }
66 }
67
68 expBackoff.lastError = *err
69 expBackoff.lastErrorTime = time.Now()
70 }
71
72 func (expBackoff *ExponentialBackoff) GenerateNoRetriesPermittedMsg(operationName string) string {
73 return fmt.Sprintf("Operation for %q failed. No retries permitted until %v (durationBeforeRetry %v). Error: %v",
74 operationName,
75 expBackoff.lastErrorTime.Add(expBackoff.durationBeforeRetry),
76 expBackoff.durationBeforeRetry,
77 expBackoff.lastError)
78 }
79
80
81 func NewExponentialBackoffError(
82 operationName string, expBackoff ExponentialBackoff) error {
83 return exponentialBackoffError{
84 operationName: operationName,
85 expBackoff: expBackoff,
86 }
87 }
88
89
90
91
92
93 func IsExponentialBackoff(err error) bool {
94 switch err.(type) {
95 case exponentialBackoffError:
96 return true
97 default:
98 return false
99 }
100 }
101
102
103
104
105
106 type exponentialBackoffError struct {
107 operationName string
108 expBackoff ExponentialBackoff
109 }
110
111 var _ error = exponentialBackoffError{}
112
113 func (err exponentialBackoffError) Error() string {
114 return fmt.Sprintf(
115 "Failed to create operation with name %q. An operation with that name failed at %v. No retries permitted until %v (%v). Last error: %q.",
116 err.operationName,
117 err.expBackoff.lastErrorTime,
118 err.expBackoff.lastErrorTime.Add(err.expBackoff.durationBeforeRetry),
119 err.expBackoff.durationBeforeRetry,
120 err.expBackoff.lastError)
121 }
122
View as plain text