-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbackoff.go
69 lines (55 loc) · 1.22 KB
/
backoff.go
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package backoff
import (
"fmt"
"math/rand"
"time"
)
type (
// Policy implements a backoff policy, randomizing its delays.
Policy struct {
Intervals []int
LogMessageHandler func(message string)
}
)
// Perform loops through each interval, calls the provided anonymous function,
// sleeps if it fails, and returns a boolean of the state.
func (p Policy) Perform(f func() (bool, error)) (bool, error) {
var errors Errors
for i := 0; i < len(p.Intervals); i++ {
ok, err := f()
if err != nil {
errors = append(errors, err)
}
if !ok {
p.sleep(i)
continue
}
return true, nil
}
if len(errors) > 0 {
return false, errors
}
return false, nil
}
func (p Policy) jitter(millis int) int {
if millis == 0 {
return 0
}
// 50 to 150%
// x = 100; (100/2 + rand(0..100); e.g: 50 + 72 = 122
return millis/2 + rand.Intn(millis)
}
func (p Policy) sleep(n int) {
if n >= len(p.Intervals) {
n = len(p.Intervals) - 1
}
duration := time.Duration(p.jitter(p.Intervals[n])) * time.Millisecond
if duration != 0 && p.LogMessageHandler != nil {
p.LogMessageHandler(
fmt.Sprintf(
"Backing off for %.2fs (attempt %d/%d)", duration.Seconds(), n+1, len(p.Intervals),
),
)
}
time.Sleep(duration)
}