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 }