Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(217)

Side by Side Diff: worker/notifyworker.go

Issue 12198044: worker: Introducing StringsWorker (Closed)
Patch Set: Created 11 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012, 2013 Canonical Ltd. 1 // Copyright 2012, 2013 Canonical Ltd.
2 // Licensed under the AGPLv3, see LICENCE file for details. 2 // Licensed under the AGPLv3, see LICENCE file for details.
3 3
4 package worker 4 package worker
5 5
6 import ( 6 import (
7 "launchpad.net/tomb" 7 "launchpad.net/tomb"
8 8
9 "launchpad.net/juju-core/state/api" 9 "launchpad.net/juju-core/state/api"
10 "launchpad.net/juju-core/state/watcher" 10 "launchpad.net/juju-core/state/watcher"
11 ) 11 )
12 12
13 // notifyWorker is the internal implementation of the NotifyWorker interface 13 // notifyWorker is the internal implementation of the NotifyWorker
14 // interface
14 type notifyWorker struct { 15 type notifyWorker struct {
15 16
16 // Internal structure 17 // Internal structure
17 tomb tomb.Tomb 18 tomb tomb.Tomb
18 19
19 // handler is what will handle when events are triggered 20 // handler is what will handle when events are triggered
20 » handler WatchHandler 21 » handler NotifyWatchHandler
21 22
22 » // closedHandler is set to watcher.MustErr, but that panic()s, so we 23 » // closedHandler is set to watcher.MustErr, but that panic()s, so
23 » // let the test suite override it. 24 » // we let the test suite override it.
24 closedHandler func(watcher.Errer) error 25 closedHandler func(watcher.Errer) error
rog 2013/08/01 11:18:47 can we just call this mustErr, as that represents
dimitern 2013/08/01 12:53:54 Done.
25 } 26 }
26 27
27 // NotifyWorker encapsulates the logic for a worker which is based on a 28 // NotifyWorker encapsulates the logic for a worker which is based on
28 // NotifyWatcher. We do a bit of setup, and then spin waiting for the watcher 29 // a NotifyWatcher. We do a bit of setup, and then spin waiting for
29 // to trigger or for us to be killed, and then teardown cleanly. 30 // the watcher to trigger or for us to be killed, and then teardown
30 type NotifyWorker interface { 31 // cleanly.
31 » // Wait for the NotifyWorker to finish what it is doing an exit 32 type NotifyWorker CommonWorker
rog 2013/08/01 11:18:47 I don't think we need this type. Let's just make N
dimitern 2013/08/01 12:53:54 Done.
32 » Wait() error
33 33
34 » // Kill the running worker, indicating that it should stop what it is 34 // NotifyWatchHandler implements the business logic that is triggered
35 » // doing and exit. Killing a running worker should return error = nil 35 // as part of watching a NotifyWatcher.
36 » // from Wait. 36 type NotifyWatchHandler interface {
37 » Kill()
38 37
39 » // Stop will call both Kill and then Wait for the worker to exit. 38 » // SetUp starts the handler, this should create the watcher we
40 » Stop() error 39 » // will be waiting on for more events. SetUp can return a Watcher
41 } 40 » // even if there is an error, and NotifyWorker will make sure to
42 41 » // stop the Watcher.
43 // WatchHandler implements the business logic that is triggered as part of
44 // watching a NotifyWatcher.
45 type WatchHandler interface {
46
47 » // SetUp starts the handler, this should create the watcher we will be
48 » // waiting on for more events. SetUp can return a Watcher even if there
49 » // is an error, and NotifyWorker will make sure to stop the Watcher.
50 SetUp() (api.NotifyWatcher, error) 42 SetUp() (api.NotifyWatcher, error)
51 43
52 // TearDown should cleanup any resources that are left around 44 // TearDown should cleanup any resources that are left around
53 TearDown() error 45 TearDown() error
54 46
55 » // Handle is called when the Watcher has indicated there are changes, 47 » // Handle is called when the Watcher has indicated there are
56 » // do whatever work is necessary to process it 48 » // changes, do whatever work is necessary to process it
57 Handle() error 49 Handle() error
58 50
59 » // String is used when reporting. It is required because NotifyWatcher 51 » // String is used when reporting. It is required because
60 » // is wrapping the WatchHandler, but the WatchHandler is the 52 » // NotifyWatcher is wrapping the NotifyWatchHandler, but the
61 » // interesting (identifying) logic. 53 » // NotifyWatchHandler is the interesting (identifying) logic.
62 String() string 54 String() string
rog 2013/08/01 11:18:47 I don't think we need a String method at all. It w
dimitern 2013/08/01 12:53:54 Done.
63 } 55 }
64 56
65 // NewNotifyWorker starts a new worker running the business logic from the 57 // NewNotifyWorker starts a new worker running the business logic from the
66 // handler. The worker loop is started in another goroutine as a side effect of 58 // handler. The worker loop is started in another goroutine as a side effect of
67 // calling this. 59 // calling this.
68 func NewNotifyWorker(handler WatchHandler) NotifyWorker { 60 func NewNotifyWorker(handler NotifyWatchHandler) NotifyWorker {
rog 2013/08/01 11:18:47 I think this should return a Worker.
dimitern 2013/08/01 12:53:54 Done.
69 nw := &notifyWorker{ 61 nw := &notifyWorker{
70 handler: handler, 62 handler: handler,
71 closedHandler: watcher.MustErr, 63 closedHandler: watcher.MustErr,
72 } 64 }
73 go func() { 65 go func() {
74 defer nw.tomb.Done() 66 defer nw.tomb.Done()
75 nw.tomb.Kill(nw.loop()) 67 nw.tomb.Kill(nw.loop())
76 }() 68 }()
77 return nw 69 return nw
78 } 70 }
79 71
80 // Kill the loop with no-error 72 // Kill the loop with no-error
81 func (nw *notifyWorker) Kill() { 73 func (nw *notifyWorker) Kill() {
82 nw.tomb.Kill(nil) 74 nw.tomb.Kill(nil)
83 } 75 }
84 76
85 // Stop kils the worker and waits for it to exit 77 // Stop kils the worker and waits for it to exit
86 func (nw *notifyWorker) Stop() error { 78 func (nw *notifyWorker) Stop() error {
rog 2013/08/01 11:18:47 I don't think we need to bother implementing this
dimitern 2013/08/01 12:53:54 Done. As discussed, worker.Stop(x) can be used ins
87 nw.tomb.Kill(nil) 79 nw.tomb.Kill(nil)
88 return nw.tomb.Wait() 80 return nw.tomb.Wait()
89 } 81 }
90 82
91 // Wait for the looping to finish 83 // Wait for the looping to finish
92 func (nw *notifyWorker) Wait() error { 84 func (nw *notifyWorker) Wait() error {
93 return nw.tomb.Wait() 85 return nw.tomb.Wait()
94 } 86 }
95 87
96 // String returns a nice description of this worker, taken from the underlying W atchHandler 88 // String returns a nice description of this worker, taken from the underlying W atchHandler
97 func (nw *notifyWorker) String() string { 89 func (nw *notifyWorker) String() string {
98 return nw.handler.String() 90 return nw.handler.String()
99 } 91 }
100 92
101 // TearDown the handler, but ensure any error is propagated 93 func notifyHandlerTearDown(handler NotifyWatchHandler, t *tomb.Tomb) {
rog 2013/08/01 11:18:47 how about this? func propagateTearDown(handler in
dimitern 2013/08/01 12:53:54 Done.
102 func handlerTearDown(handler WatchHandler, t *tomb.Tomb) { 94 » // Tear down the handler, but ensure any error is propagated
mue 2013/08/01 10:35:24 Why the comment in the method?
dimitern 2013/08/01 12:53:54 Because it was describing what's being done, rathe
103 if err := handler.TearDown(); err != nil { 95 if err := handler.TearDown(); err != nil {
104 t.Kill(err) 96 t.Kill(err)
105 } 97 }
106 } 98 }
107 99
108 func (nw *notifyWorker) loop() error { 100 func (nw *notifyWorker) loop() error {
109 var w api.NotifyWatcher 101 var w api.NotifyWatcher
110 var err error 102 var err error
111 » defer handlerTearDown(nw.handler, &nw.tomb) 103 » defer notifyHandlerTearDown(nw.handler, &nw.tomb)
rog 2013/08/01 11:18:47 I'm not convinced that it's right to call TearDown
dimitern 2013/08/01 12:53:54 As I understand it, you propose to call this after
112 if w, err = nw.handler.SetUp(); err != nil { 104 if w, err = nw.handler.SetUp(); err != nil {
113 if w != nil { 105 if w != nil {
114 // We don't bother to propogate an error, because we 106 // We don't bother to propogate an error, because we
rog 2013/08/01 11:18:47 s/propo/propa/
dimitern 2013/08/01 12:53:54 Done.
115 // already have an error 107 // already have an error
116 w.Stop() 108 w.Stop()
117 } 109 }
118 return err 110 return err
119 } 111 }
120 defer watcher.Stop(w, &nw.tomb) 112 defer watcher.Stop(w, &nw.tomb)
121 for { 113 for {
122 select { 114 select {
123 case <-nw.tomb.Dying(): 115 case <-nw.tomb.Dying():
124 return tomb.ErrDying 116 return tomb.ErrDying
125 case _, ok := <-w.Changes(): 117 case _, ok := <-w.Changes():
126 if !ok { 118 if !ok {
127 return nw.closedHandler(w) 119 return nw.closedHandler(w)
128 } 120 }
129 if err := nw.handler.Handle(); err != nil { 121 if err := nw.handler.Handle(); err != nil {
130 return err 122 return err
131 } 123 }
132 } 124 }
133 } 125 }
134 panic("unreachable")
rog 2013/08/01 11:18:47 yay!
135 } 126 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b