github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/workers/dumb.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package workers
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  
    10  	"github.com/juju/juju/worker"
    11  	"github.com/juju/juju/worker/catacomb"
    12  )
    13  
    14  // DumbConfig holds a DumbWorkers' dependencies.
    15  type DumbConfig struct {
    16  	Factory Factory
    17  	Logger  loggo.Logger
    18  }
    19  
    20  // Validate returns an error if config cannot drive a DumbWorkers.
    21  func (config DumbConfig) Validate() error {
    22  	if config.Factory == nil {
    23  		return errors.NotValidf("nil Factory")
    24  	}
    25  	if config.Logger == (loggo.Logger{}) {
    26  		return errors.NotValidf("uninitialized Logger")
    27  	}
    28  	return nil
    29  }
    30  
    31  // NewDumbWorkers returns a worker that will live until Kill()ed,
    32  // giving access to a set of sub-workers needed by the state package.
    33  //
    34  // These workers may die of their own accord at any time, and will
    35  // not be replaced; they will also all be stopped before Wait returns.
    36  func NewDumbWorkers(config DumbConfig) (_ *DumbWorkers, err error) {
    37  	if err := config.Validate(); err != nil {
    38  		return nil, errors.Trace(err)
    39  	}
    40  	logger := config.Logger
    41  
    42  	w := &DumbWorkers{config: config}
    43  	defer func() {
    44  		if err == nil {
    45  			return
    46  		}
    47  		// this is ok because cleanup can handle nil fields
    48  		if cleanupErr := w.cleanup(); cleanupErr != nil {
    49  			logger.Errorf("while aborting DumbWorkers creation: %v", cleanupErr)
    50  		}
    51  	}()
    52  
    53  	logger.Debugf("starting leadership lease manager")
    54  	w.leadershipWorker, err = config.Factory.NewLeadershipWorker()
    55  	if err != nil {
    56  		return nil, errors.Annotatef(err, "cannot create leadership lease manager")
    57  	}
    58  
    59  	logger.Debugf("starting singular lease manager")
    60  	w.singularWorker, err = config.Factory.NewSingularWorker()
    61  	if err != nil {
    62  		return nil, errors.Annotatef(err, "cannot create singular lease manager")
    63  	}
    64  
    65  	logger.Debugf("starting transaction log watcher")
    66  	w.txnLogWorker, err = config.Factory.NewTxnLogWorker()
    67  	if err != nil {
    68  		return nil, errors.Annotatef(err, "cannot create transaction log watcher")
    69  	}
    70  
    71  	logger.Debugf("starting presence watcher")
    72  	w.presenceWorker, err = config.Factory.NewPresenceWorker()
    73  	if err != nil {
    74  		return nil, errors.Annotatef(err, "cannot create presence watcher")
    75  	}
    76  
    77  	// note that we specifically *don't* want to use catacomb's
    78  	// worker-tracking features like Add and Init, because we want
    79  	// this type to live until externally killed, regardless of the
    80  	// state of the inner workers. We're just using catacomb because
    81  	// it's slightly safer than tomb.
    82  	err = catacomb.Invoke(catacomb.Plan{
    83  		Site: &w.catacomb,
    84  		Work: w.run,
    85  	})
    86  	if err != nil {
    87  		return nil, errors.Trace(err)
    88  	}
    89  	return w, nil
    90  }
    91  
    92  // DumbWorkers holds references to standard state workers. The workers
    93  // are not guaranteed to be running; but they are guaranteed to be
    94  // stopped when the DumbWorkers is stopped.
    95  type DumbWorkers struct {
    96  	config           DumbConfig
    97  	catacomb         catacomb.Catacomb
    98  	txnLogWorker     TxnLogWorker
    99  	presenceWorker   PresenceWorker
   100  	leadershipWorker LeaseWorker
   101  	singularWorker   LeaseWorker
   102  }
   103  
   104  // TxnLogWatcher is part of the Workers interface.
   105  func (dw *DumbWorkers) TxnLogWatcher() TxnLogWatcher {
   106  	return dw.txnLogWorker
   107  }
   108  
   109  // PresenceWatcher is part of the Workers interface.
   110  func (dw *DumbWorkers) PresenceWatcher() PresenceWatcher {
   111  	return dw.presenceWorker
   112  }
   113  
   114  // LeadershipManager is part of the Workers interface.
   115  func (dw *DumbWorkers) LeadershipManager() LeaseManager {
   116  	return dw.leadershipWorker
   117  }
   118  
   119  // SingularManager is part of the Workers interface.
   120  func (dw *DumbWorkers) SingularManager() LeaseManager {
   121  	return dw.singularWorker
   122  }
   123  
   124  // Kill is part of the worker.Worker interface.
   125  func (dw *DumbWorkers) Kill() {
   126  	dw.catacomb.Kill(nil)
   127  }
   128  
   129  // Wait is part of the worker.Worker interface.
   130  func (dw *DumbWorkers) Wait() error {
   131  	return dw.catacomb.Wait()
   132  }
   133  
   134  func (dw *DumbWorkers) run() error {
   135  	<-dw.catacomb.Dying()
   136  	if err := dw.cleanup(); err != nil {
   137  		return errors.Trace(err)
   138  	}
   139  	return dw.catacomb.ErrDying()
   140  }
   141  
   142  func (dw *DumbWorkers) cleanup() error {
   143  	var errs []error
   144  	handle := func(name string, w worker.Worker) {
   145  		if w == nil {
   146  			return
   147  		}
   148  		if err := worker.Stop(w); err != nil {
   149  			errs = append(errs, errors.Annotatef(err, "error stopping %s", name))
   150  		}
   151  	}
   152  
   153  	handle("transaction log watcher", dw.txnLogWorker)
   154  	handle("presence watcher", dw.presenceWorker)
   155  	handle("leadership lease manager", dw.leadershipWorker)
   156  	handle("singular lease manager", dw.singularWorker)
   157  	if len(errs) > 0 {
   158  		for _, err := range errs[1:] {
   159  			dw.config.Logger.Errorf("while stopping state workers: %v", err)
   160  		}
   161  		return errs[0]
   162  	}
   163  
   164  	dw.config.Logger.Debugf("stopped state workers without error")
   165  	return nil
   166  }