github.com/decred/dcrlnd@v0.7.6/ticker/ticker.go (about) 1 package ticker 2 3 import "time" 4 5 // Ticker defines a resumable ticker interface, whose activity can be toggled to 6 // free up resources during periods of inactivity. 7 // 8 // Example of resuming ticker: 9 // 10 // ticker.Resume() // can remove to keep inactive at first 11 // defer ticker.Stop() 12 // for { 13 // select { 14 // case <-ticker.Tick(): 15 // if shouldGoInactive { 16 // ticker.Pause() 17 // continue 18 // } 19 // ... 20 // 21 // case <-otherEvent: 22 // ... 23 // if shouldGoActive { 24 // ticker.Resume() 25 // } 26 // } 27 // 28 // NOTE: ONE DOES NOT SIMPLY assume that Tickers are safe for concurrent access. 29 type Ticker interface { 30 // Ticks returns a read-only channel delivering ticks according to a 31 // prescribed interval. The value returned does not need to be the same 32 // channel, and may be nil. 33 // 34 // NOTE: Callers should assume that reads from Ticks() are stale after 35 // any invocations of Resume, Pause, or Stop. 36 Ticks() <-chan time.Time 37 38 // Resume starts or resumes the underlying ticker, such that Ticks() 39 // will fire at regular intervals. After calling Resume, Ticks() should 40 // minimally send ticks at the prescribed interval. 41 // 42 // NOTE: It MUST be safe to call Resume at any time, and more than once 43 // successively. 44 Resume() 45 46 // Pause suspends the underlying ticker, such that Ticks() stops 47 // signaling at regular intervals. After calling Pause, the ticker 48 // should not send any ticks scheduled with the chosen interval. Forced 49 // ticks are still permissible, as in the case of the Force Ticker. 50 // 51 // NOTE: It MUST be safe to call Pause at any time, and more than once 52 // successively. 53 Pause() 54 55 // Stop suspends the underlying ticker, such that Ticks() stops 56 // signaling at regular intervals, and permanently frees up any 57 // remaining resources. 58 // 59 // NOTE: The behavior of a Ticker is undefined after calling Stop. 60 Stop() 61 } 62 63 // T is the production implementation of the resumable Ticker interface. This 64 // allows various components to toggle their need for tick events, which may 65 // vary depending on system load. 66 type T struct { 67 // interval is the desired duration between ticks when active. 68 interval time.Duration 69 70 // ticker is the ephemeral, underlying time.Ticker. We keep a reference 71 // to this ticker so that it can be stopped and cleaned up on Pause or 72 // Stop. 73 ticker *time.Ticker 74 } 75 76 // A compile-time constraint to ensure T satisfies the Ticker interface. 77 var _ Ticker = (*T)(nil) 78 79 // New returns a new ticker that signals with the given interval when not 80 // paused. The ticker starts off inactive. 81 func New(interval time.Duration) *T { 82 return &T{ 83 interval: interval, 84 } 85 } 86 87 // Ticks returns a receive-only channel that delivers times at the ticker's 88 // prescribed interval. This method returns nil when the ticker is paused. 89 // 90 // NOTE: Part of the Ticker interface. 91 func (t *T) Ticks() <-chan time.Time { 92 if t.ticker == nil { 93 return nil 94 } 95 return t.ticker.C 96 } 97 98 // Resume starts underlying time.Ticker and causes the ticker to begin 99 // delivering scheduled events. 100 // 101 // NOTE: Part of the Ticker interface. 102 func (t *T) Resume() { 103 if t.ticker == nil { 104 t.ticker = time.NewTicker(t.interval) 105 } 106 } 107 108 // Pause suspends the underlying ticker, such that Ticks() stops signaling at 109 // regular intervals. 110 // 111 // NOTE: Part of the Ticker interface. 112 func (t *T) Pause() { 113 if t.ticker != nil { 114 t.ticker.Stop() 115 t.ticker = nil 116 } 117 } 118 119 // Stop suspends the underlying ticker, such that Ticks() stops signaling at 120 // regular intervals, and permanently frees up any resources. For this 121 // implementation, this is equivalent to Pause. 122 // 123 // NOTE: Part of the Ticker interface. 124 func (t *T) Stop() { 125 t.Pause() 126 }