Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
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 "launchpad.net/juju-core/state/api" | |
10 "launchpad.net/juju-core/state/watcher" | |
11 ) | |
12 | |
13 // stringsWorker is the internal implementation of the StringsWorker | |
14 // interface | |
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 // closedHandler is set to watcher.MustErr, but that panic()s, so | |
22 // we let the test suite override it. | |
23 closedHandler func(watcher.Errer) error | |
rog
2013/08/01 11:18:47
s/closedHandler/mustErr/
dimitern
2013/08/01 12:53:54
Done.
| |
24 } | |
25 | |
26 // StringsWorker encapsulates the logic for a worker which is based on | |
27 // a StringsWatcher. We do a bit of setup, and then spin waiting for | |
28 // the watcher to trigger of for use to be killed, and then torn down | |
29 // cleanly. | |
30 type StringsWorker CommonWorker | |
31 | |
32 // StringsWatchHandler implements the business logic triggered as part | |
33 // of watching a StringsWorker. | |
34 type StringsWatchHandler interface { | |
35 // SetUp starts the handler, this should create the watcher we | |
36 // will be waiting on for more events. SetUp can return a Watcher | |
37 // even if there is an error, and StringsWorker will make sure to | |
38 // stop the Watcher. | |
39 SetUp() (api.StringsWatcher, error) | |
40 | |
41 // TearDown should cleanup any resources that are left around | |
42 TearDown() error | |
43 | |
44 // Handle is called when the Watcher has indicated there are | |
45 // changes, do whatever work is necessary to process it | |
46 Handle(changes []string) error | |
47 | |
48 // String is used when reporting. It is required because | |
49 // StringsWatcher is wrapping the StringsWatchHandler, but the | |
50 // StringsWatchHandler is the interesting (identifying) logic. | |
51 String() string | |
rog
2013/08/01 11:18:47
d
dimitern
2013/08/01 12:53:54
Done.
| |
52 } | |
53 | |
54 // NewStringsWorker starts a new worker running the business logic | |
55 // from the handler. The worker loop is started in another goroutine | |
56 // as a side effect of calling this. | |
57 func NewStringsWorker(handler StringsWatchHandler) StringsWorker { | |
rog
2013/08/01 11:18:47
I think this should return a Worker.
dimitern
2013/08/01 12:53:54
Done.
| |
58 sw := &stringsWorker{ | |
59 handler: handler, | |
60 closedHandler: watcher.MustErr, | |
61 } | |
62 go func() { | |
63 defer sw.tomb.Done() | |
64 sw.tomb.Kill(sw.loop()) | |
65 }() | |
66 return sw | |
67 } | |
68 | |
69 // Kill the loop with no-error | |
70 func (sw *stringsWorker) Kill() { | |
71 sw.tomb.Kill(nil) | |
72 } | |
73 | |
74 // Stop kils the worker and waits for it to exit | |
75 func (sw *stringsWorker) Stop() error { | |
rog
2013/08/01 11:18:47
d
dimitern
2013/08/01 12:53:54
Done.
| |
76 sw.tomb.Kill(nil) | |
77 return sw.tomb.Wait() | |
78 } | |
79 | |
80 // Wait for the looping to finish | |
81 func (sw *stringsWorker) Wait() error { | |
82 return sw.tomb.Wait() | |
83 } | |
84 | |
85 // String returns a nice description of this worker, taken from the | |
86 // underlying StringsWatchHandler | |
87 func (sw *stringsWorker) String() string { | |
rog
2013/08/01 11:18:47
d
dimitern
2013/08/01 12:53:54
Done.
| |
88 return sw.handler.String() | |
89 } | |
90 | |
91 func stringsHandlerTearDown(handler StringsWatchHandler, t *tomb.Tomb) { | |
rog
2013/08/01 11:18:47
d (given a generic version elsewhere)
dimitern
2013/08/01 12:53:54
Done.
| |
92 // Tear down the handler, but ensure any error is propagated | |
93 if err := handler.TearDown(); err != nil { | |
94 t.Kill(err) | |
95 } | |
96 } | |
97 | |
98 func (sw *stringsWorker) loop() error { | |
99 var w api.StringsWatcher | |
100 var err error | |
rog
2013/08/01 11:18:47
Rather than explicitly declaring these, how about:
dimitern
2013/08/01 12:53:54
Done.
| |
101 defer stringsHandlerTearDown(sw.handler, &sw.tomb) | |
102 if w, err = sw.handler.SetUp(); err != nil { | |
103 if w != nil { | |
104 // We don't bother to propogate an error, because we | |
105 // already have an error | |
106 w.Stop() | |
107 } | |
108 return err | |
109 } | |
110 defer watcher.Stop(w, &sw.tomb) | |
111 for { | |
112 select { | |
113 case <-sw.tomb.Dying(): | |
114 return tomb.ErrDying | |
115 case changes, ok := <-w.Changes(): | |
116 if !ok { | |
117 return sw.closedHandler(w) | |
118 } | |
119 if err := sw.handler.Handle(changes); err != nil { | |
120 return err | |
121 } | |
122 } | |
123 } | |
124 } | |
OLD | NEW |