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  }