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