github.com/pure-x-eth/consensus_tm@v0.0.0-20230502163723-e3c2ff987250/libs/timer/throttle_timer.go (about) 1 package timer 2 3 import ( 4 "time" 5 6 tmsync "github.com/pure-x-eth/consensus_tm/libs/sync" 7 ) 8 9 /* 10 ThrottleTimer fires an event at most "dur" after each .Set() call. 11 If a short burst of .Set() calls happens, ThrottleTimer fires once. 12 If a long continuous burst of .Set() calls happens, ThrottleTimer fires 13 at most once every "dur". 14 */ 15 type ThrottleTimer struct { 16 Name string 17 Ch chan struct{} 18 quit chan struct{} 19 dur time.Duration 20 21 mtx tmsync.Mutex 22 timer *time.Timer 23 isSet bool 24 } 25 26 func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer { 27 var ch = make(chan struct{}) 28 var quit = make(chan struct{}) 29 var t = &ThrottleTimer{Name: name, Ch: ch, dur: dur, quit: quit} 30 t.mtx.Lock() 31 t.timer = time.AfterFunc(dur, t.fireRoutine) 32 t.mtx.Unlock() 33 t.timer.Stop() 34 return t 35 } 36 37 func (t *ThrottleTimer) fireRoutine() { 38 t.mtx.Lock() 39 defer t.mtx.Unlock() 40 select { 41 case t.Ch <- struct{}{}: 42 t.isSet = false 43 case <-t.quit: 44 // do nothing 45 default: 46 t.timer.Reset(t.dur) 47 } 48 } 49 50 func (t *ThrottleTimer) Set() { 51 t.mtx.Lock() 52 defer t.mtx.Unlock() 53 if !t.isSet { 54 t.isSet = true 55 t.timer.Reset(t.dur) 56 } 57 } 58 59 func (t *ThrottleTimer) Unset() { 60 t.mtx.Lock() 61 defer t.mtx.Unlock() 62 t.isSet = false 63 t.timer.Stop() 64 } 65 66 // For ease of .Stop()'ing services before .Start()'ing them, 67 // we ignore .Stop()'s on nil ThrottleTimers 68 func (t *ThrottleTimer) Stop() bool { 69 if t == nil { 70 return false 71 } 72 close(t.quit) 73 t.mtx.Lock() 74 defer t.mtx.Unlock() 75 return t.timer.Stop() 76 }