-
Notifications
You must be signed in to change notification settings - Fork 405
/
backoff.go
69 lines (55 loc) · 1.29 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 common
import (
"context"
"math"
"math/rand"
"sync"
"time"
)
type BoxTime struct{}
func (BoxTime) Now() time.Time { return time.Now() }
func (BoxTime) Sleep(d time.Duration) { time.Sleep(d) }
func (BoxTime) After(d time.Duration) <-chan time.Time { return time.After(d) }
type Backoff int
func (b *Backoff) Sleep(ctx context.Context) {
const (
maxexp = 7
interval = 25 * time.Millisecond
)
rng := defaultRNG
clock := defaultClock
// 25-50ms, 50-100ms, 100-200ms, 200-400ms, 400-800ms, 800-1600ms, 1600-3200ms, 3200-6400ms
d := time.Duration(math.Pow(2, float64(*b))) * interval
d += (d * time.Duration(rng.Float64()))
select {
case <-ctx.Done():
case <-clock.After(d):
}
if *b < maxexp {
(*b)++
}
}
var (
defaultRNG = NewRNG(time.Now().UnixNano())
defaultClock = BoxTime{}
)
func NewRNG(seed int64) *rand.Rand {
return rand.New(&lockedSource{src: rand.NewSource(seed)})
}
// taken from go1.5.1 math/rand/rand.go +233-250
// bla bla if it puts a hole in the earth don't sue them
type lockedSource struct {
lk sync.Mutex
src rand.Source
}
func (r *lockedSource) Int63() (n int64) {
r.lk.Lock()
n = r.src.Int63()
r.lk.Unlock()
return
}
func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.src.Seed(seed)
r.lk.Unlock()
}