github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/globalclockupdater/manifold.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package globalclockupdater 5 6 import ( 7 "time" 8 9 "github.com/juju/clock" 10 "github.com/juju/errors" 11 "gopkg.in/juju/worker.v1" 12 "gopkg.in/juju/worker.v1/dependency" 13 14 "github.com/juju/juju/core/globalclock" 15 workerstate "github.com/juju/juju/worker/state" 16 ) 17 18 // ManifoldConfig holds the information necessary to run a GlobalClockUpdater 19 // worker in a dependency.Engine. 20 type ManifoldConfig struct { 21 ClockName string 22 StateName string 23 LeaseManagerName string 24 RaftName string 25 26 NewWorker func(Config) (worker.Worker, error) 27 UpdateInterval time.Duration 28 BackoffDelay time.Duration 29 Logger Logger 30 } 31 32 func (config ManifoldConfig) Validate() error { 33 if config.ClockName == "" { 34 return errors.NotValidf("empty ClockName") 35 } 36 if config.StateName == "" && config.LeaseManagerName == "" { 37 return errors.NotValidf("both StateName and LeaseManagerName empty") 38 } 39 if config.StateName != "" && config.LeaseManagerName != "" { 40 return errors.NewNotValid(nil, "only one of StateName and LeaseManagerName can be set") 41 } 42 if config.StateName != "" && config.RaftName != "" { 43 return errors.NewNotValid(nil, "RaftName only valid with LeaseManagerName") 44 } 45 if config.NewWorker == nil { 46 return errors.NotValidf("nil NewWorker") 47 } 48 if config.UpdateInterval <= 0 { 49 return errors.NotValidf("non-positive UpdateInterval") 50 } 51 if config.BackoffDelay <= 0 { 52 return errors.NotValidf("non-positive BackoffDelay") 53 } 54 if config.Logger == nil { 55 return errors.NotValidf("nil Logger") 56 } 57 return nil 58 } 59 60 // Manifold returns a dependency.Manifold that will run a global clock 61 // updater worker. 62 func Manifold(config ManifoldConfig) dependency.Manifold { 63 inputs := []string{config.ClockName} 64 if config.StateName != "" { 65 inputs = append(inputs, config.StateName) 66 } else { 67 inputs = append(inputs, config.LeaseManagerName) 68 } 69 if config.RaftName != "" { 70 inputs = append(inputs, config.RaftName) 71 } 72 return dependency.Manifold{ 73 Inputs: inputs, 74 Start: config.start, 75 } 76 } 77 78 // start is a method on ManifoldConfig because it's more readable than a closure. 79 func (config ManifoldConfig) start(context dependency.Context) (worker.Worker, error) { 80 if err := config.Validate(); err != nil { 81 return nil, errors.Trace(err) 82 } 83 84 var clock clock.Clock 85 if err := context.Get(config.ClockName, &clock); err != nil { 86 return nil, errors.Trace(err) 87 } 88 89 if config.RaftName != "" { 90 // We don't need anything from raft directly, but if it's set 91 // ensure it's running before continuing. 92 if err := context.Get(config.RaftName, nil); err != nil { 93 return nil, errors.Trace(err) 94 } 95 } 96 97 cleanup := func() error { return nil } 98 var updaterFunc func() (globalclock.Updater, error) 99 if config.StateName != "" { 100 var stTracker workerstate.StateTracker 101 if err := context.Get(config.StateName, &stTracker); err != nil { 102 return nil, errors.Trace(err) 103 } 104 statePool, err := stTracker.Use() 105 if err != nil { 106 return nil, errors.Trace(err) 107 } 108 cleanup = stTracker.Done 109 updaterFunc = statePool.SystemState().GlobalClockUpdater 110 } else { 111 112 var updater globalclock.Updater 113 if err := context.Get(config.LeaseManagerName, &updater); err != nil { 114 return nil, errors.Trace(err) 115 } 116 updaterFunc = func() (globalclock.Updater, error) { 117 return updater, nil 118 } 119 } 120 121 worker, err := config.NewWorker(Config{ 122 NewUpdater: updaterFunc, 123 LocalClock: clock, 124 UpdateInterval: config.UpdateInterval, 125 BackoffDelay: config.BackoffDelay, 126 Logger: config.Logger, 127 }) 128 if err != nil { 129 cleanup() 130 return nil, errors.Trace(err) 131 } 132 133 go func() { 134 worker.Wait() 135 cleanup() 136 }() 137 return worker, nil 138 }