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 }