-
Notifications
You must be signed in to change notification settings - Fork 0
/
ticker.go
123 lines (111 loc) · 3.58 KB
/
ticker.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
package ticker
import "time"
// Ticker defines a resumable ticker interface, whose activity can be toggled to
// free up resources during periods of inactivity.
//
// Example of resuming ticker:
//
// ticker.Resume() // can remove to keep inactive at first
// defer ticker.Stop()
// for {
// select {
// case <-ticker.Tick():
// if shouldGoInactive {
// ticker.Pause()
// continue
// }
// ...
//
// case <-otherEvent:
// ...
// if shouldGoActive {
// ticker.Resume()
// }
// }
//
// NOTE: ONE DOES NOT SIMPLY assume that Tickers are safe for concurrent access.
type Ticker interface {
// Ticks returns a read-only channel delivering ticks according to a
// prescribed interval. The value returned does not need to be the same
// channel, and may be nil.
//
// NOTE: Callers should assume that reads from Ticks() are stale after
// any invocations of Resume, Pause, or Stop.
Ticks() <-chan time.Time
// Resume starts or resumes the underlying ticker, such that Ticks()
// will fire at regular intervals. After calling Resume, Ticks() should
// minimally send ticks at the prescribed interval.
//
// NOTE: It MUST be safe to call Resume at any time, and more than once
// successively.
Resume()
// Pause suspends the underlying ticker, such that Ticks() stops
// signaling at regular intervals. After calling Pause, the ticker
// should not send any ticks scheduled with the chosen interval. Forced
// ticks are still permissible, as in the case of the Mock Ticker.
//
// NOTE: It MUST be safe to call Pause at any time, and more than once
// successively.
Pause()
// Stop suspends the underlying ticker, such that Ticks() stops
// signaling at regular intervals, and permanently frees up any
// remaining resources.
//
// NOTE: The behavior of a Ticker is undefined after calling Stop.
Stop()
}
// ticker is the production implementation of the resumable Ticker interface.
// This allows various components to toggle their need for tick events, which
// may vary depending on system load.
type ticker struct {
// interval is the desired duration between ticks when active.
interval time.Duration
// ticker is the ephemeral, underlying time.Ticker. We keep a reference
// to this ticker so that it can be stopped and cleaned up on Pause or
// Stop.
ticker *time.Ticker
}
// New returns a new ticker that signals with the given interval when not
// paused. The ticker starts off inactive.
func New(interval time.Duration) Ticker {
return &ticker{
interval: interval,
}
}
// Ticks returns a receive-only channel that delivers times at the ticker's
// prescribed interval. This method returns nil when the ticker is paused.
//
// NOTE: Part of the Ticker interface.
func (t *ticker) Ticks() <-chan time.Time {
if t.ticker == nil {
return nil
}
return t.ticker.C
}
// Resumes starts underlying time.Ticker and causes the ticker to begin
// delivering scheduled events.
//
// NOTE: Part of the Ticker interface.
func (t *ticker) Resume() {
if t.ticker == nil {
t.ticker = time.NewTicker(t.interval)
}
}
// Pause suspends the underlying ticker, such that Ticks() stops signaling at
// regular intervals.
//
// NOTE: Part of the Ticker interface.
func (t *ticker) Pause() {
if t.ticker != nil {
t.ticker.Stop()
t.ticker = nil
}
}
// Stop suspends the underlying ticker, such that Ticks() stops signaling at
// regular intervals, and permanently frees up any resources. For this
// implementation, this is equivalent to Pause.
//
// NOTE: Part of the Ticker interface.
func (t *ticker) Stop() {
t.Pause()
}