github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/watcher/legacy/stringsworker.go (about)

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