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  }