github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/workers/dumb.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package workers 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 10 "github.com/juju/juju/worker" 11 "github.com/juju/juju/worker/catacomb" 12 ) 13 14 // DumbConfig holds a DumbWorkers' dependencies. 15 type DumbConfig struct { 16 Factory Factory 17 Logger loggo.Logger 18 } 19 20 // Validate returns an error if config cannot drive a DumbWorkers. 21 func (config DumbConfig) Validate() error { 22 if config.Factory == nil { 23 return errors.NotValidf("nil Factory") 24 } 25 if config.Logger == (loggo.Logger{}) { 26 return errors.NotValidf("uninitialized Logger") 27 } 28 return nil 29 } 30 31 // NewDumbWorkers returns a worker that will live until Kill()ed, 32 // giving access to a set of sub-workers needed by the state package. 33 // 34 // These workers may die of their own accord at any time, and will 35 // not be replaced; they will also all be stopped before Wait returns. 36 func NewDumbWorkers(config DumbConfig) (_ *DumbWorkers, err error) { 37 if err := config.Validate(); err != nil { 38 return nil, errors.Trace(err) 39 } 40 logger := config.Logger 41 42 w := &DumbWorkers{config: config} 43 defer func() { 44 if err == nil { 45 return 46 } 47 // this is ok because cleanup can handle nil fields 48 if cleanupErr := w.cleanup(); cleanupErr != nil { 49 logger.Errorf("while aborting DumbWorkers creation: %v", cleanupErr) 50 } 51 }() 52 53 logger.Debugf("starting leadership lease manager") 54 w.leadershipWorker, err = config.Factory.NewLeadershipWorker() 55 if err != nil { 56 return nil, errors.Annotatef(err, "cannot create leadership lease manager") 57 } 58 59 logger.Debugf("starting singular lease manager") 60 w.singularWorker, err = config.Factory.NewSingularWorker() 61 if err != nil { 62 return nil, errors.Annotatef(err, "cannot create singular lease manager") 63 } 64 65 logger.Debugf("starting transaction log watcher") 66 w.txnLogWorker, err = config.Factory.NewTxnLogWorker() 67 if err != nil { 68 return nil, errors.Annotatef(err, "cannot create transaction log watcher") 69 } 70 71 logger.Debugf("starting presence watcher") 72 w.presenceWorker, err = config.Factory.NewPresenceWorker() 73 if err != nil { 74 return nil, errors.Annotatef(err, "cannot create presence watcher") 75 } 76 77 // note that we specifically *don't* want to use catacomb's 78 // worker-tracking features like Add and Init, because we want 79 // this type to live until externally killed, regardless of the 80 // state of the inner workers. We're just using catacomb because 81 // it's slightly safer than tomb. 82 err = catacomb.Invoke(catacomb.Plan{ 83 Site: &w.catacomb, 84 Work: w.run, 85 }) 86 if err != nil { 87 return nil, errors.Trace(err) 88 } 89 return w, nil 90 } 91 92 // DumbWorkers holds references to standard state workers. The workers 93 // are not guaranteed to be running; but they are guaranteed to be 94 // stopped when the DumbWorkers is stopped. 95 type DumbWorkers struct { 96 config DumbConfig 97 catacomb catacomb.Catacomb 98 txnLogWorker TxnLogWorker 99 presenceWorker PresenceWorker 100 leadershipWorker LeaseWorker 101 singularWorker LeaseWorker 102 } 103 104 // TxnLogWatcher is part of the Workers interface. 105 func (dw *DumbWorkers) TxnLogWatcher() TxnLogWatcher { 106 return dw.txnLogWorker 107 } 108 109 // PresenceWatcher is part of the Workers interface. 110 func (dw *DumbWorkers) PresenceWatcher() PresenceWatcher { 111 return dw.presenceWorker 112 } 113 114 // LeadershipManager is part of the Workers interface. 115 func (dw *DumbWorkers) LeadershipManager() LeaseManager { 116 return dw.leadershipWorker 117 } 118 119 // SingularManager is part of the Workers interface. 120 func (dw *DumbWorkers) SingularManager() LeaseManager { 121 return dw.singularWorker 122 } 123 124 // Kill is part of the worker.Worker interface. 125 func (dw *DumbWorkers) Kill() { 126 dw.catacomb.Kill(nil) 127 } 128 129 // Wait is part of the worker.Worker interface. 130 func (dw *DumbWorkers) Wait() error { 131 return dw.catacomb.Wait() 132 } 133 134 func (dw *DumbWorkers) run() error { 135 <-dw.catacomb.Dying() 136 if err := dw.cleanup(); err != nil { 137 return errors.Trace(err) 138 } 139 return dw.catacomb.ErrDying() 140 } 141 142 func (dw *DumbWorkers) cleanup() error { 143 var errs []error 144 handle := func(name string, w worker.Worker) { 145 if w == nil { 146 return 147 } 148 if err := worker.Stop(w); err != nil { 149 errs = append(errs, errors.Annotatef(err, "error stopping %s", name)) 150 } 151 } 152 153 handle("transaction log watcher", dw.txnLogWorker) 154 handle("presence watcher", dw.presenceWorker) 155 handle("leadership lease manager", dw.leadershipWorker) 156 handle("singular lease manager", dw.singularWorker) 157 if len(errs) > 0 { 158 for _, err := range errs[1:] { 159 dw.config.Logger.Errorf("while stopping state workers: %v", err) 160 } 161 return errs[0] 162 } 163 164 dw.config.Logger.Debugf("stopped state workers without error") 165 return nil 166 }