github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/client/consul/check.go (about)

     1  package consul
     2  
     3  import (
     4  	"log"
     5  	"math/rand"
     6  	"sync"
     7  	"time"
     8  
     9  	cstructs "github.com/hashicorp/nomad/client/driver/structs"
    10  )
    11  
    12  // CheckRunner runs a given check in a specific interval and update a
    13  // corresponding Consul TTL check
    14  type CheckRunner struct {
    15  	check    Check
    16  	runCheck func(Check)
    17  	logger   *log.Logger
    18  	stop     bool
    19  	stopCh   chan struct{}
    20  	stopLock sync.Mutex
    21  
    22  	started     bool
    23  	startedLock sync.Mutex
    24  }
    25  
    26  // NewCheckRunner configures and returns a CheckRunner
    27  func NewCheckRunner(check Check, runCheck func(Check), logger *log.Logger) *CheckRunner {
    28  	cr := CheckRunner{
    29  		check:    check,
    30  		runCheck: runCheck,
    31  		logger:   logger,
    32  		stopCh:   make(chan struct{}),
    33  	}
    34  	return &cr
    35  }
    36  
    37  // Start is used to start the check. The check runs until stop is called
    38  func (r *CheckRunner) Start() {
    39  	r.startedLock.Lock()
    40  	defer r.startedLock.Unlock()
    41  	if r.started {
    42  		return
    43  	}
    44  	r.stopLock.Lock()
    45  	defer r.stopLock.Unlock()
    46  	go r.run()
    47  	r.started = true
    48  }
    49  
    50  // Stop is used to stop the check.
    51  func (r *CheckRunner) Stop() {
    52  	r.stopLock.Lock()
    53  	defer r.stopLock.Unlock()
    54  	if !r.stop {
    55  		r.stop = true
    56  		close(r.stopCh)
    57  	}
    58  }
    59  
    60  // run is invoked by a goroutine to run until Stop() is called
    61  func (r *CheckRunner) run() {
    62  	// Get the randomized initial pause time
    63  	initialPauseTime := randomStagger(r.check.Interval())
    64  	r.logger.Printf("[DEBUG] agent: pausing %v before first invocation of %s", initialPauseTime, r.check.ID())
    65  	next := time.NewTimer(initialPauseTime)
    66  	for {
    67  		select {
    68  		case <-next.C:
    69  			r.runCheck(r.check)
    70  			next.Reset(r.check.Interval())
    71  		case <-r.stopCh:
    72  			next.Stop()
    73  			return
    74  		}
    75  	}
    76  }
    77  
    78  // Check is an interface which check providers can implement for Nomad to run
    79  type Check interface {
    80  	Run() *cstructs.CheckResult
    81  	ID() string
    82  	Interval() time.Duration
    83  	Timeout() time.Duration
    84  }
    85  
    86  // Returns a random stagger interval between 0 and the duration
    87  func randomStagger(intv time.Duration) time.Duration {
    88  	return time.Duration(uint64(rand.Int63()) % uint64(intv))
    89  }