github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/pruner/worker.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package pruner 5 6 import ( 7 "time" 8 9 "github.com/juju/clock" 10 "github.com/juju/errors" 11 "github.com/juju/worker/v3/catacomb" 12 13 "github.com/juju/juju/core/watcher" 14 "github.com/juju/juju/environs/config" 15 ) 16 17 // logger is here to stop the desire of creating a package level logger. 18 // Don't do this, instead pass one through as config to the worker. 19 type logger interface{} 20 21 var ( 22 _ logger = struct{}{} 23 ) 24 25 //go:generate go run go.uber.org/mock/mockgen -package mocks -destination mocks/mocks_facade.go github.com/juju/juju/worker/pruner Facade 26 27 // Facade represents an API that implements status history pruning. 28 type Facade interface { 29 Prune(time.Duration, int) error 30 WatchForModelConfigChanges() (watcher.NotifyWatcher, error) 31 ModelConfig() (*config.Config, error) 32 } 33 34 // PrunerWorker prunes status history or action records at regular intervals. 35 type PrunerWorker struct { 36 catacomb catacomb.Catacomb 37 config Config 38 } 39 40 // Kill is defined on worker.Worker. 41 func (w *PrunerWorker) Kill() { 42 w.catacomb.Kill(nil) 43 } 44 45 // Wait is defined on worker.Worker. 46 func (w *PrunerWorker) Wait() error { 47 return w.catacomb.Wait() 48 } 49 50 // Catacomb returns the prune worker's catacomb. 51 func (w *PrunerWorker) Catacomb() *catacomb.Catacomb { 52 return &w.catacomb 53 } 54 55 // Config return the prune worker's config. 56 func (w *PrunerWorker) Config() *Config { 57 return &w.config 58 } 59 60 // Work is the main body of generic pruner loop. 61 func (w *PrunerWorker) Work(getPrunerConfig func(*config.Config) (time.Duration, uint)) error { 62 modelConfigWatcher, err := w.config.Facade.WatchForModelConfigChanges() 63 if err != nil { 64 return errors.Trace(err) 65 } 66 err = w.catacomb.Add(modelConfigWatcher) 67 if err != nil { 68 return errors.Trace(err) 69 } 70 71 var ( 72 maxAge time.Duration 73 maxCollectionMB uint 74 modelConfigChanges = modelConfigWatcher.Changes() 75 // We will also get an initial event, but need to ensure that event is 76 // received before doing any pruning. 77 ) 78 79 var timer clock.Timer 80 var timerCh <-chan time.Time 81 for { 82 select { 83 case <-w.catacomb.Dying(): 84 return w.catacomb.ErrDying() 85 86 case _, ok := <-modelConfigChanges: 87 if !ok { 88 return errors.New("model configuration watcher closed") 89 } 90 modelConfig, err := w.config.Facade.ModelConfig() 91 if err != nil { 92 return errors.Annotate(err, "cannot load model configuration") 93 } 94 95 newMaxAge, newMaxCollectionMB := getPrunerConfig(modelConfig) 96 97 if newMaxAge != maxAge || newMaxCollectionMB != maxCollectionMB { 98 w.config.Logger.Infof("pruner config: max age: %v, max collection size %dM for %s (%s)", 99 newMaxAge, newMaxCollectionMB, modelConfig.Name(), modelConfig.UUID()) 100 maxAge = newMaxAge 101 maxCollectionMB = newMaxCollectionMB 102 } 103 if timer == nil { 104 timer = w.config.Clock.NewTimer(w.config.PruneInterval) 105 timerCh = timer.Chan() 106 } 107 108 case <-timerCh: 109 err := w.config.Facade.Prune(maxAge, int(maxCollectionMB)) 110 if err != nil { 111 return errors.Trace(err) 112 } 113 timer.Reset(w.config.PruneInterval) 114 } 115 } 116 }