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