...
1 package backoff
2
3 import (
4 "context"
5 "time"
6 )
7
8 type ExponentialInterval struct {
9 current float64
10 maxInterval float64
11 minInterval float64
12 multiplier float64
13 jitter jitter
14 }
15
16 const (
17 defaultMaxInterval = float64(time.Minute)
18 defaultMinInterval = float64(500 * time.Millisecond)
19 defaultMultiplier = 1.5
20 )
21
22 func NewExponentialInterval(options ...ExponentialOption) *ExponentialInterval {
23 jitterFactor := 0.0
24 maxInterval := defaultMaxInterval
25 minInterval := defaultMinInterval
26 multiplier := defaultMultiplier
27 var rng Random
28
29 for _, option := range options {
30 switch option.Ident() {
31 case identJitterFactor{}:
32 jitterFactor = option.Value().(float64)
33 case identMaxInterval{}:
34 maxInterval = float64(option.Value().(time.Duration))
35 case identMinInterval{}:
36 minInterval = float64(option.Value().(time.Duration))
37 case identMultiplier{}:
38 multiplier = option.Value().(float64)
39 case identRNG{}:
40 rng = option.Value().(Random)
41 }
42 }
43
44 if minInterval > maxInterval {
45 minInterval = maxInterval
46 }
47 if multiplier <= 1 {
48 multiplier = defaultMultiplier
49 }
50
51 return &ExponentialInterval{
52 maxInterval: maxInterval,
53 minInterval: minInterval,
54 multiplier: multiplier,
55 jitter: newJitter(jitterFactor, rng),
56 }
57 }
58
59 func (g *ExponentialInterval) Next() time.Duration {
60 var next float64
61 if g.current == 0 {
62 next = g.minInterval
63 } else {
64 next = g.current * g.multiplier
65 }
66
67 if next > g.maxInterval {
68 next = g.maxInterval
69 }
70 if next < g.minInterval {
71 next = g.minInterval
72 }
73
74
75 next = g.jitter.apply(next)
76 g.current = next
77 return time.Duration(next)
78 }
79
80 type ExponentialPolicy struct {
81 cOptions []ControllerOption
82 igOptions []ExponentialOption
83 }
84
85 func NewExponentialPolicy(options ...ExponentialOption) *ExponentialPolicy {
86 var cOptions []ControllerOption
87 var igOptions []ExponentialOption
88
89 for _, option := range options {
90 switch opt := option.(type) {
91 case ControllerOption:
92 cOptions = append(cOptions, opt)
93 default:
94 igOptions = append(igOptions, opt)
95 }
96 }
97
98 return &ExponentialPolicy{
99 cOptions: cOptions,
100 igOptions: igOptions,
101 }
102 }
103
104 func (p *ExponentialPolicy) Start(ctx context.Context) Controller {
105 ig := NewExponentialInterval(p.igOptions...)
106 return newController(ctx, ig, p.cOptions...)
107 }
108
View as plain text