github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/agent/comm/timeout.go (about) 1 package comm 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 // TimeoutWatcher tracks and handles command timeout within the agent. 9 type TimeoutWatcher struct { 10 duration time.Duration 11 timer *time.Timer 12 stop <-chan struct{} 13 disabled bool 14 15 mutex sync.Mutex 16 } 17 18 func NewTimeoutWatcher(stopChan <-chan struct{}) *TimeoutWatcher { 19 // TODO: replace this with a context for cancellation, and be 20 // able to eliminate the constructor 21 return &TimeoutWatcher{stop: stopChan} 22 } 23 24 // SetDuration sets the duration after which a timeout is triggered. 25 func (tw *TimeoutWatcher) SetDuration(duration time.Duration) { 26 tw.mutex.Lock() 27 defer tw.mutex.Unlock() 28 29 tw.duration = duration 30 } 31 32 // CheckIn resets the idle timer to zero. 33 func (tw *TimeoutWatcher) CheckIn() { 34 tw.mutex.Lock() 35 defer tw.mutex.Unlock() 36 37 if tw.timer != nil && !tw.disabled { 38 tw.timer.Reset(tw.duration) 39 } 40 } 41 42 // NotifyTimeouts sends a signal on sigChan whenever the timeout threshold of 43 // the current execution stage is reached. 44 func (tw *TimeoutWatcher) NotifyTimeouts(sigChan chan<- Signal) { 45 go func() { 46 tw.mutex.Lock() 47 if tw.timer == nil { 48 if tw.duration <= 0 { 49 tw.mutex.Unlock() 50 panic("can't wait for timeouts with negative duration") 51 } 52 tw.timer = time.NewTimer(tw.duration) 53 } 54 tw.mutex.Unlock() 55 56 select { 57 case <-tw.timer.C: 58 // if execution reaches here, it's timed out. 59 // send the time out signal on sigChan 60 sigChan <- IdleTimeout 61 return 62 case <-tw.stop: 63 return 64 } 65 }() 66 }