2016-03-24 17:06:40 +00:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
2016-03-25 02:00:24 +00:00
|
|
|
"log"
|
|
|
|
"math/rand"
|
|
|
|
"sync"
|
2016-03-24 20:05:08 +00:00
|
|
|
"time"
|
|
|
|
|
2016-03-24 17:06:40 +00:00
|
|
|
cstructs "github.com/hashicorp/nomad/client/driver/structs"
|
|
|
|
)
|
|
|
|
|
2016-03-25 04:17:33 +00:00
|
|
|
// CheckRunner runs a given check in a specific interval and update a
|
2016-03-25 02:30:02 +00:00
|
|
|
// corresponding Consul TTL check
|
2016-03-25 04:17:33 +00:00
|
|
|
type CheckRunner struct {
|
2016-03-25 02:00:24 +00:00
|
|
|
check Check
|
|
|
|
runCheck func(Check)
|
|
|
|
logger *log.Logger
|
|
|
|
stop bool
|
|
|
|
stopCh chan struct{}
|
|
|
|
stopLock sync.Mutex
|
2016-03-24 20:05:08 +00:00
|
|
|
|
2016-03-25 02:00:24 +00:00
|
|
|
started bool
|
|
|
|
startedLock sync.Mutex
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
|
|
|
|
2016-03-25 04:17:33 +00:00
|
|
|
// NewCheckRunner configures and returns a CheckRunner
|
|
|
|
func NewCheckRunner(check Check, runCheck func(Check), logger *log.Logger) *CheckRunner {
|
2016-03-25 17:36:31 +00:00
|
|
|
cr := CheckRunner{
|
2016-03-25 02:00:24 +00:00
|
|
|
check: check,
|
|
|
|
runCheck: runCheck,
|
|
|
|
logger: logger,
|
|
|
|
stopCh: make(chan struct{}),
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
2016-03-25 17:36:31 +00:00
|
|
|
return &cr
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
|
|
|
|
2016-03-25 02:30:02 +00:00
|
|
|
// Start is used to start the check. The check runs until stop is called
|
2016-03-25 04:17:33 +00:00
|
|
|
func (r *CheckRunner) Start() {
|
|
|
|
r.startedLock.Lock()
|
2016-03-25 17:36:31 +00:00
|
|
|
defer r.startedLock.Unlock()
|
2016-03-25 04:17:33 +00:00
|
|
|
if r.started {
|
2016-03-25 02:00:24 +00:00
|
|
|
return
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
2016-03-25 04:17:33 +00:00
|
|
|
r.stopLock.Lock()
|
|
|
|
defer r.stopLock.Unlock()
|
|
|
|
go r.run()
|
2016-03-25 17:36:31 +00:00
|
|
|
r.started = true
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
|
|
|
|
2016-03-25 02:30:02 +00:00
|
|
|
// Stop is used to stop the check.
|
2016-03-25 04:17:33 +00:00
|
|
|
func (r *CheckRunner) Stop() {
|
|
|
|
r.stopLock.Lock()
|
|
|
|
defer r.stopLock.Unlock()
|
|
|
|
if !r.stop {
|
|
|
|
r.stop = true
|
|
|
|
close(r.stopCh)
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-25 02:00:24 +00:00
|
|
|
// run is invoked by a goroutine to run until Stop() is called
|
2016-03-25 04:17:33 +00:00
|
|
|
func (r *CheckRunner) run() {
|
2016-03-25 02:00:24 +00:00
|
|
|
// Get the randomized initial pause time
|
2016-03-25 04:17:33 +00:00
|
|
|
initialPauseTime := randomStagger(r.check.Interval())
|
|
|
|
r.logger.Printf("[DEBUG] agent: pausing %v before first invocation of %s", initialPauseTime, r.check.ID())
|
2016-03-25 02:00:24 +00:00
|
|
|
next := time.After(initialPauseTime)
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-next:
|
2016-03-25 04:17:33 +00:00
|
|
|
r.runCheck(r.check)
|
|
|
|
next = time.After(r.check.Interval())
|
|
|
|
case <-r.stopCh:
|
2016-03-25 02:00:24 +00:00
|
|
|
return
|
|
|
|
}
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-25 02:30:02 +00:00
|
|
|
// Check is an interface which check providers can implement for Nomad to run
|
2016-03-25 02:00:24 +00:00
|
|
|
type Check interface {
|
|
|
|
Run() *cstructs.CheckResult
|
|
|
|
ID() string
|
|
|
|
Interval() time.Duration
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|
|
|
|
|
2016-03-25 02:00:24 +00:00
|
|
|
// Returns a random stagger interval between 0 and the duration
|
|
|
|
func randomStagger(intv time.Duration) time.Duration {
|
|
|
|
return time.Duration(uint64(rand.Int63()) % uint64(intv))
|
2016-03-24 20:05:08 +00:00
|
|
|
}
|