-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbackoff.go
More file actions
84 lines (70 loc) · 1.72 KB
/
Copy pathbackoff.go
File metadata and controls
84 lines (70 loc) · 1.72 KB
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package mongoproxy
import (
"math/rand"
"time"
)
/*
Interface BackoffPolicy can be used to compute the next backoff value when
retrying requests to a server or other contended resource. For instance:
for {
if ok := sendRequest(); ok {
break
}
next, ok := policy.Next(); ok {
time.Sleep(next)
} else {
break
}
}
*/
type BackoffPolicy interface {
Next() (next time.Duration, ok bool)
}
// A backoff policy that always returns the same value for Next()
type ConstantBackoffPolicy struct {
i, maxRetries int
interval time.Duration
}
func NewConstantBackoffPolicy(maxRetries int, interval time.Duration) BackoffPolicy {
return &ConstantBackoffPolicy{maxRetries: maxRetries, interval: interval}
}
func (p *ConstantBackoffPolicy) Next() (next time.Duration, ok bool) {
if p.i < p.maxRetries {
ok = true
next = p.interval
p.i++
}
return
}
// A backoff policy that returns a value in 2^i * interval + rand[0, interval)
// for Next(), where i is the index of the retry
type ExpBackoffPolicy struct {
i, maxRetries int
interval time.Duration
}
func NewExpBackoffPolicy(maxRetries int, interval time.Duration) BackoffPolicy {
return &ExpBackoffPolicy{maxRetries: maxRetries, interval: interval}
}
func (p *ExpBackoffPolicy) Next() (next time.Duration, ok bool) {
if p.i < p.maxRetries {
ok = true
cur := int64(p.interval)
next = time.Duration((1<<uint(p.i))*cur + rand.Int63n(cur))
p.i++
}
return
}
// A helper which sleeps with the value returned by policy.Next() as long as the
// block provided returns true.
func CallWithBackoff(block func() bool, policy BackoffPolicy) {
for {
if !block() {
break
}
if next, ok := policy.Next(); ok {
time.Sleep(next)
} else {
break
}
}
}