github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/worker/periodicworker.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package worker 5 6 import ( 7 "errors" 8 "time" 9 10 "launchpad.net/tomb" 11 ) 12 13 // ErrKilled can be returned by the PeriodicWorkerCall to signify that 14 // the function has returned as a result of a Stop() or Kill() signal 15 // and that the function was able to stop cleanly 16 var ErrKilled = errors.New("worker killed") 17 18 // periodicWorker implements the worker returned by NewPeriodicWorker. 19 type periodicWorker struct { 20 tomb tomb.Tomb 21 } 22 23 type PeriodicWorkerCall func(stop <-chan struct{}) error 24 25 // NewPeriodicWorker returns a worker that runs the given function continually 26 // sleeping for sleepDuration in between each call, until Kill() is called 27 // The stopCh argument will be closed when the worker is killed. The error returned 28 // by the doWork function will be returned by the worker's Wait function. 29 func NewPeriodicWorker(call PeriodicWorkerCall, period time.Duration) Worker { 30 w := &periodicWorker{} 31 go func() { 32 defer w.tomb.Done() 33 w.tomb.Kill(w.run(call, period)) 34 }() 35 return w 36 } 37 38 func (w *periodicWorker) run(call PeriodicWorkerCall, period time.Duration) error { 39 timer := time.NewTimer(0) 40 stop := w.tomb.Dying() 41 for { 42 select { 43 case <-stop: 44 return tomb.ErrDying 45 case <-timer.C: 46 if err := call(stop); err != nil { 47 if err == ErrKilled { 48 return tomb.ErrDying 49 } 50 return err 51 } 52 } 53 timer.Reset(period) 54 } 55 } 56 57 // Kill implements Worker.Kill() and will close the channel given to the doWork 58 // function. 59 func (w *periodicWorker) Kill() { 60 w.tomb.Kill(nil) 61 } 62 63 // Wait implements Worker.Wait(), and will return the error returned by 64 // the doWork function. 65 func (w *periodicWorker) Wait() error { 66 return w.tomb.Wait() 67 }