github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/charmrevision/worker.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package charmrevision 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/tomb.v2" 13 ) 14 15 // RevisionUpdater exposes the "single" capability required by the worker. 16 // As the worker gains more responsibilities, it will likely need more; see 17 // storageprovisioner for a helpful model to grow towards. 18 type RevisionUpdater interface { 19 20 // UpdateLatestRevisions causes the environment to be scanned, the charm 21 // store to be interrogated, and model representations of updated charms 22 // to be stored in the environment. 23 // 24 // That is sufficiently complex that the logic should be implemented by 25 // the worker, not directly on the apiserver; as this functionality needs 26 // to change/mature, please migrate responsibilities down to the worker 27 // and grow this interface to match. 28 UpdateLatestRevisions() error 29 } 30 31 // Config defines the operation of a charm revision updater worker. 32 type Config struct { 33 34 // RevisionUpdater is the worker's view of the controller. 35 RevisionUpdater RevisionUpdater 36 37 // Clock is the worker's view of time. 38 Clock clock.Clock 39 40 // Period is the time between charm revision updates. 41 Period time.Duration 42 } 43 44 // Validate returns an error if the configuration cannot be expected 45 // to start a functional worker. 46 func (config Config) Validate() error { 47 if config.RevisionUpdater == nil { 48 return errors.NotValidf("nil RevisionUpdater") 49 } 50 if config.Clock == nil { 51 return errors.NotValidf("nil Clock") 52 } 53 if config.Period <= 0 { 54 return errors.NotValidf("non-positive Period") 55 } 56 return nil 57 } 58 59 // NewWorker returns a worker that calls UpdateLatestRevisions on the 60 // configured RevisionUpdater, once when started and subsequently every 61 // Period. 62 func NewWorker(config Config) (worker.Worker, error) { 63 if err := config.Validate(); err != nil { 64 return nil, errors.Trace(err) 65 } 66 w := &revisionUpdateWorker{ 67 config: config, 68 } 69 w.tomb.Go(w.loop) 70 return w, nil 71 } 72 73 type revisionUpdateWorker struct { 74 tomb tomb.Tomb 75 config Config 76 } 77 78 func (ruw *revisionUpdateWorker) loop() error { 79 var delay time.Duration 80 for { 81 select { 82 case <-ruw.tomb.Dying(): 83 return tomb.ErrDying 84 case <-ruw.config.Clock.After(delay): 85 err := ruw.config.RevisionUpdater.UpdateLatestRevisions() 86 if err != nil { 87 return errors.Trace(err) 88 } 89 } 90 delay = ruw.config.Period 91 } 92 } 93 94 // Kill is part of the worker.Worker interface. 95 func (ruw *revisionUpdateWorker) Kill() { 96 ruw.tomb.Kill(nil) 97 } 98 99 // Wait is part of the worker.Worker interface. 100 func (ruw *revisionUpdateWorker) Wait() error { 101 return ruw.tomb.Wait() 102 }