github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/stringsworker.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package worker
     5  
     6  import (
     7  	"launchpad.net/tomb"
     8  
     9  	apiWatcher "github.com/juju/juju/api/watcher"
    10  	"github.com/juju/juju/state/watcher"
    11  )
    12  
    13  // stringsWorker is the internal implementation of the Worker
    14  // interface, using a StringsWatcher for handling changes.
    15  type stringsWorker struct {
    16  	tomb tomb.Tomb
    17  
    18  	// handler is what will be called when events are triggered.
    19  	handler StringsWatchHandler
    20  }
    21  
    22  // StringsWatchHandler implements the business logic triggered as part
    23  // of watching a StringsWatcher.
    24  type StringsWatchHandler interface {
    25  	// SetUp starts the handler, this should create the watcher we
    26  	// will be waiting on for more events. SetUp can return a Watcher
    27  	// even if there is an error, and strings Worker will make sure to
    28  	// stop the watcher.
    29  	SetUp() (apiWatcher.StringsWatcher, error)
    30  
    31  	// TearDown should cleanup any resources that are left around
    32  	TearDown() error
    33  
    34  	// Handle is called when the Watcher has indicated there are
    35  	// changes, do whatever work is necessary to process it
    36  	Handle(changes []string) error
    37  }
    38  
    39  // NewStringsWorker starts a new worker running the business logic
    40  // from the handler. The worker loop is started in another goroutine
    41  // as a side effect of calling this.
    42  func NewStringsWorker(handler StringsWatchHandler) Worker {
    43  	sw := &stringsWorker{
    44  		handler: handler,
    45  	}
    46  	go func() {
    47  		defer sw.tomb.Done()
    48  		sw.tomb.Kill(sw.loop())
    49  	}()
    50  	return sw
    51  }
    52  
    53  // Kill the loop with no-error
    54  func (sw *stringsWorker) Kill() {
    55  	sw.tomb.Kill(nil)
    56  }
    57  
    58  // Wait for the looping to finish
    59  func (sw *stringsWorker) Wait() error {
    60  	return sw.tomb.Wait()
    61  }
    62  
    63  func (sw *stringsWorker) loop() error {
    64  	w, err := sw.handler.SetUp()
    65  	if err != nil {
    66  		if w != nil {
    67  			// We don't bother to propagate an error, because we
    68  			// already have an error
    69  			w.Stop()
    70  		}
    71  		return err
    72  	}
    73  	defer propagateTearDown(sw.handler, &sw.tomb)
    74  	defer watcher.Stop(w, &sw.tomb)
    75  	for {
    76  		select {
    77  		case <-sw.tomb.Dying():
    78  			return tomb.ErrDying
    79  		case changes, ok := <-w.Changes():
    80  			if !ok {
    81  				return ensureErr(w)
    82  			}
    83  			if err := sw.handler.Handle(changes); err != nil {
    84  				return err
    85  			}
    86  		}
    87  	}
    88  }