github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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/loggo"
    12  	"gopkg.in/juju/worker.v1/catacomb"
    13  
    14  	"github.com/juju/juju/core/watcher"
    15  	"github.com/juju/juju/environs/config"
    16  )
    17  
    18  var logger = loggo.GetLogger("juju.worker.pruner")
    19  
    20  // Facade represents an API that implements status history pruning.
    21  type Facade interface {
    22  	Prune(time.Duration, int) error
    23  	WatchForModelConfigChanges() (watcher.NotifyWatcher, error)
    24  	ModelConfig() (*config.Config, error)
    25  }
    26  
    27  // Worker prunes status history records at regular intervals.
    28  type PrunerWorker struct {
    29  	catacomb catacomb.Catacomb
    30  	config   Config
    31  }
    32  
    33  // Kill is defined on worker.Worker.
    34  func (w *PrunerWorker) Kill() {
    35  	w.catacomb.Kill(nil)
    36  }
    37  
    38  // Wait is defined on worker.Worker.
    39  func (w *PrunerWorker) Wait() error {
    40  	return w.catacomb.Wait()
    41  }
    42  
    43  // returns the prune worker's catacomb
    44  func (w *PrunerWorker) Catacomb() *catacomb.Catacomb {
    45  	return &w.catacomb
    46  }
    47  
    48  // return the prune worker's config
    49  func (w *PrunerWorker) Config() *Config {
    50  	return &w.config
    51  }
    52  
    53  // body of generic pruner loop
    54  func (w *PrunerWorker) Work(getPrunerConfig func(*config.Config) (time.Duration, uint)) error {
    55  	modelConfigWatcher, err := w.config.Facade.WatchForModelConfigChanges()
    56  	if err != nil {
    57  		return errors.Trace(err)
    58  	}
    59  	err = w.catacomb.Add(modelConfigWatcher)
    60  	if err != nil {
    61  		return errors.Trace(err)
    62  	}
    63  
    64  	var (
    65  		maxAge             time.Duration
    66  		maxCollectionMB    uint
    67  		modelConfigChanges = modelConfigWatcher.Changes()
    68  		// We will also get an initial event, but need to ensure that event is
    69  		// received before doing any pruning.
    70  	)
    71  
    72  	var timer clock.Timer
    73  	var timerCh <-chan time.Time
    74  	for {
    75  		select {
    76  		case <-w.catacomb.Dying():
    77  			return w.catacomb.ErrDying()
    78  
    79  		case _, ok := <-modelConfigChanges:
    80  			if !ok {
    81  				return errors.New("model configuration watcher closed")
    82  			}
    83  			modelConfig, err := w.config.Facade.ModelConfig()
    84  			if err != nil {
    85  				return errors.Annotate(err, "cannot load model configuration")
    86  			}
    87  
    88  			newMaxAge, newMaxCollectionMB := getPrunerConfig(modelConfig)
    89  
    90  			if newMaxAge != maxAge || newMaxCollectionMB != maxCollectionMB {
    91  				logger.Infof("status history config: max age: %v, max collection size %dM for %s (%s)",
    92  					newMaxAge, newMaxCollectionMB, modelConfig.Name(), modelConfig.UUID())
    93  				maxAge = newMaxAge
    94  				maxCollectionMB = newMaxCollectionMB
    95  			}
    96  			if timer == nil {
    97  				timer = w.config.Clock.NewTimer(w.config.PruneInterval)
    98  				timerCh = timer.Chan()
    99  			}
   100  
   101  		case <-timerCh:
   102  			err := w.config.Facade.Prune(maxAge, int(maxCollectionMB))
   103  			if err != nil {
   104  				return errors.Trace(err)
   105  			}
   106  			timer.Reset(w.config.PruneInterval)
   107  		}
   108  	}
   109  }