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  }