github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/resumer/resumer.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package resumer 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/juju/worker/catacomb" 11 "github.com/juju/loggo" 12 "github.com/juju/utils/clock" 13 ) 14 15 var logger = loggo.GetLogger("juju.worker.resumer") 16 17 // Facade defines the interface for types capable of resuming 18 // transactions. 19 type Facade interface { 20 21 // ResumeTransactions resumes all pending transactions. 22 ResumeTransactions() error 23 } 24 25 // Config holds the dependencies and configuration necessary to 26 // drive a Resumer. 27 type Config struct { 28 Facade Facade 29 Clock clock.Clock 30 Interval time.Duration 31 } 32 33 // Validate returns an error if config cannot be expected to drive 34 // a Resumer. 35 func (config Config) Validate() error { 36 if config.Facade == nil { 37 return errors.NotValidf("nil Facade") 38 } 39 if config.Clock == nil { 40 return errors.NotValidf("nil Clock") 41 } 42 if config.Interval <= 0 { 43 return errors.NotValidf("non-positive Interval") 44 } 45 return nil 46 } 47 48 // Resumer is responsible for periodically resuming all pending 49 // transactions. 50 type Resumer struct { 51 catacomb catacomb.Catacomb 52 config Config 53 } 54 55 // NewResumer returns a new Resumer or an error. If the Resumer is 56 // not nil, the caller is responsible for stopping it via `Kill()` 57 // and handling any error returned from `Wait()`. 58 var NewResumer = func(config Config) (*Resumer, error) { 59 if err := config.Validate(); err != nil { 60 return nil, errors.Trace(err) 61 } 62 rr := &Resumer{config: config} 63 err := catacomb.Invoke(catacomb.Plan{ 64 Site: &rr.catacomb, 65 Work: rr.loop, 66 }) 67 if err != nil { 68 return nil, errors.Trace(err) 69 } 70 return rr, nil 71 } 72 73 // Kill is part of the worker.Worker interface. 74 func (rr *Resumer) Kill() { 75 rr.catacomb.Kill(nil) 76 } 77 78 // Wait is part of the worker.Worker interface. 79 func (rr *Resumer) Wait() error { 80 return rr.catacomb.Wait() 81 } 82 83 func (rr *Resumer) loop() error { 84 var interval time.Duration 85 for { 86 select { 87 case <-rr.catacomb.Dying(): 88 return rr.catacomb.ErrDying() 89 case <-rr.config.Clock.After(interval): 90 err := rr.config.Facade.ResumeTransactions() 91 if err != nil { 92 return errors.Annotate(err, "cannot resume transactions") 93 } 94 } 95 interval = rr.config.Interval 96 } 97 }