github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/globalclockupdater/manifold.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package globalclockupdater
     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/juju/worker.v1/dependency"
    13  
    14  	"github.com/juju/juju/core/globalclock"
    15  	workerstate "github.com/juju/juju/worker/state"
    16  )
    17  
    18  // ManifoldConfig holds the information necessary to run a GlobalClockUpdater
    19  // worker in a dependency.Engine.
    20  type ManifoldConfig struct {
    21  	ClockName        string
    22  	StateName        string
    23  	LeaseManagerName string
    24  	RaftName         string
    25  
    26  	NewWorker      func(Config) (worker.Worker, error)
    27  	UpdateInterval time.Duration
    28  	BackoffDelay   time.Duration
    29  	Logger         Logger
    30  }
    31  
    32  func (config ManifoldConfig) Validate() error {
    33  	if config.ClockName == "" {
    34  		return errors.NotValidf("empty ClockName")
    35  	}
    36  	if config.StateName == "" && config.LeaseManagerName == "" {
    37  		return errors.NotValidf("both StateName and LeaseManagerName empty")
    38  	}
    39  	if config.StateName != "" && config.LeaseManagerName != "" {
    40  		return errors.NewNotValid(nil, "only one of StateName and LeaseManagerName can be set")
    41  	}
    42  	if config.StateName != "" && config.RaftName != "" {
    43  		return errors.NewNotValid(nil, "RaftName only valid with LeaseManagerName")
    44  	}
    45  	if config.NewWorker == nil {
    46  		return errors.NotValidf("nil NewWorker")
    47  	}
    48  	if config.UpdateInterval <= 0 {
    49  		return errors.NotValidf("non-positive UpdateInterval")
    50  	}
    51  	if config.BackoffDelay <= 0 {
    52  		return errors.NotValidf("non-positive BackoffDelay")
    53  	}
    54  	if config.Logger == nil {
    55  		return errors.NotValidf("nil Logger")
    56  	}
    57  	return nil
    58  }
    59  
    60  // Manifold returns a dependency.Manifold that will run a global clock
    61  // updater worker.
    62  func Manifold(config ManifoldConfig) dependency.Manifold {
    63  	inputs := []string{config.ClockName}
    64  	if config.StateName != "" {
    65  		inputs = append(inputs, config.StateName)
    66  	} else {
    67  		inputs = append(inputs, config.LeaseManagerName)
    68  	}
    69  	if config.RaftName != "" {
    70  		inputs = append(inputs, config.RaftName)
    71  	}
    72  	return dependency.Manifold{
    73  		Inputs: inputs,
    74  		Start:  config.start,
    75  	}
    76  }
    77  
    78  // start is a method on ManifoldConfig because it's more readable than a closure.
    79  func (config ManifoldConfig) start(context dependency.Context) (worker.Worker, error) {
    80  	if err := config.Validate(); err != nil {
    81  		return nil, errors.Trace(err)
    82  	}
    83  
    84  	var clock clock.Clock
    85  	if err := context.Get(config.ClockName, &clock); err != nil {
    86  		return nil, errors.Trace(err)
    87  	}
    88  
    89  	if config.RaftName != "" {
    90  		// We don't need anything from raft directly, but if it's set
    91  		// ensure it's running before continuing.
    92  		if err := context.Get(config.RaftName, nil); err != nil {
    93  			return nil, errors.Trace(err)
    94  		}
    95  	}
    96  
    97  	cleanup := func() error { return nil }
    98  	var updaterFunc func() (globalclock.Updater, error)
    99  	if config.StateName != "" {
   100  		var stTracker workerstate.StateTracker
   101  		if err := context.Get(config.StateName, &stTracker); err != nil {
   102  			return nil, errors.Trace(err)
   103  		}
   104  		statePool, err := stTracker.Use()
   105  		if err != nil {
   106  			return nil, errors.Trace(err)
   107  		}
   108  		cleanup = stTracker.Done
   109  		updaterFunc = statePool.SystemState().GlobalClockUpdater
   110  	} else {
   111  
   112  		var updater globalclock.Updater
   113  		if err := context.Get(config.LeaseManagerName, &updater); err != nil {
   114  			return nil, errors.Trace(err)
   115  		}
   116  		updaterFunc = func() (globalclock.Updater, error) {
   117  			return updater, nil
   118  		}
   119  	}
   120  
   121  	worker, err := config.NewWorker(Config{
   122  		NewUpdater:     updaterFunc,
   123  		LocalClock:     clock,
   124  		UpdateInterval: config.UpdateInterval,
   125  		BackoffDelay:   config.BackoffDelay,
   126  		Logger:         config.Logger,
   127  	})
   128  	if err != nil {
   129  		cleanup()
   130  		return nil, errors.Trace(err)
   131  	}
   132  
   133  	go func() {
   134  		worker.Wait()
   135  		cleanup()
   136  	}()
   137  	return worker, nil
   138  }