-
Notifications
You must be signed in to change notification settings - Fork 89
/
timer.go
124 lines (106 loc) · 3.54 KB
/
timer.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2015 Canonical Ltd.
// Copyright 2015 Cloudbase Solutions SRL
// Licensed under the LGPLv3, see LICENCE file for details.
package utils
import (
"math/rand"
"time"
"github.com/juju/clock"
)
// Countdown implements a timer that will call a provided function.
// after a internally stored duration. The steps as well as min and max
// durations are declared upon initialization and depend on
// the particular implementation.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
type Countdown interface {
// Reset stops the timer and resets its duration to the minimum one.
// Start must be called to start the timer again.
Reset()
// Start starts the internal timer.
// At the end of the timer, if Reset hasn't been called in the mean time
// Func will be called and the duration is increased for the next call.
Start()
}
// NewBackoffTimer creates and initializes a new BackoffTimer
// A backoff timer starts at min and gets multiplied by factor
// until it reaches max. Jitter determines whether a small
// randomization is added to the duration.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
func NewBackoffTimer(config BackoffTimerConfig) *BackoffTimer {
return &BackoffTimer{
config: config,
currentDuration: config.Min,
}
}
// BackoffTimer implements Countdown.
// A backoff timer starts at min and gets multiplied by factor
// until it reaches max. Jitter determines whether a small
// randomization is added to the duration.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
type BackoffTimer struct {
config BackoffTimerConfig
timer clock.Timer
currentDuration time.Duration
}
// BackoffTimerConfig is a helper struct for backoff timer
// that encapsulates config information.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
type BackoffTimerConfig struct {
// The minimum duration after which Func is called.
Min time.Duration
// The maximum duration after which Func is called.
Max time.Duration
// Determines whether a small randomization is applied to
// the duration.
Jitter bool
// The factor by which you want the duration to increase
// every time.
Factor int64
// Func is the function that will be called when the countdown reaches 0.
Func func()
// Clock provides the AfterFunc function used to call func.
// It is exposed here so it's easier to mock it in tests.
Clock clock.Clock
}
// Start implements the Timer interface.
// Any existing timer execution is stopped before
// a new one is created.
func (t *BackoffTimer) Start() {
if t.timer != nil {
t.timer.Stop()
}
t.timer = t.config.Clock.AfterFunc(t.currentDuration, t.config.Func)
// Since it's a backoff timer we will increase
// the duration after each signal.
t.increaseDuration()
}
// Reset implements the Timer interface.
func (t *BackoffTimer) Reset() {
if t.timer != nil {
t.timer.Stop()
}
if t.currentDuration > t.config.Min {
t.currentDuration = t.config.Min
}
}
// increaseDuration will increase the duration based on
// the current value and the factor. If jitter is true
// it will add a 0.3% jitter to the final value.
func (t *BackoffTimer) increaseDuration() {
current := int64(t.currentDuration)
nextDuration := time.Duration(current * t.config.Factor)
if t.config.Jitter {
// Get a factor in [-1; 1].
randFactor := (rand.Float64() * 2) - 1
jitter := float64(nextDuration) * randFactor * 0.03
nextDuration = nextDuration + time.Duration(jitter)
}
if nextDuration > t.config.Max {
nextDuration = t.config.Max
}
t.currentDuration = nextDuration
}