mirror of
https://github.com/coredns/coredns.git
synced 2025-10-31 18:23:13 -04:00
* plugin/forward: on demand healtchecking Only start doing health checks when we encouner an error (any error). This uses the new pluing/pkg/up package to abstract away the actual checking. This reduces the LOC quite a bit; does need more testing, unit testing and tcpdumping a bit. * fix tests * Fix readme * Use pkg/up for healthchecks * remove unused channel * more cleanups * update readme * * Again do go generate and go build; still referencing the wrong forward repo? Anyway fixed. * Use pkg/up for doing the healtchecks to cut back on unwanted queries * Change up.Func to return an error instead of a boolean. * Drop the string target argument as it doesn't make sense. * Add healthcheck test on failing to get an upstream answer. TODO(miek): double check Forward and Lookup and how they interact with HC, and if we correctly call close() on those * actual test * Tests here * more tests * try getting rid of host * Get rid of the host indirection * Finish removing hosts * moar testing * import fmt * field is not used * docs * move some stuff * bring back health_check * maxfails=0 test * git and merging, bah * review
68 lines
1.5 KiB
Go
68 lines
1.5 KiB
Go
package up
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Probe is used to run a single Func until it returns true (indicating a target is healthy). If an Func
|
|
// is already in progress no new one will be added, i.e. there is always a maximum of 1 checks in flight.
|
|
type Probe struct {
|
|
do chan Func
|
|
stop chan bool
|
|
|
|
target string
|
|
|
|
sync.Mutex
|
|
inprogress bool
|
|
}
|
|
|
|
// Func is used to determine if a target is alive. If so this function must return nil.
|
|
type Func func() error
|
|
|
|
// New returns a pointer to an intialized Probe.
|
|
func New() *Probe {
|
|
return &Probe{stop: make(chan bool), do: make(chan Func)}
|
|
}
|
|
|
|
// Do will probe target, if a probe is already in progress this is a noop.
|
|
func (p *Probe) Do(f Func) { p.do <- f }
|
|
|
|
// Stop stops the probing.
|
|
func (p *Probe) Stop() { p.stop <- true }
|
|
|
|
// Start will start the probe manager, after which probes can be initialized with Do.
|
|
func (p *Probe) Start(interval time.Duration) { go p.start(interval) }
|
|
|
|
func (p *Probe) start(interval time.Duration) {
|
|
for {
|
|
select {
|
|
case <-p.stop:
|
|
return
|
|
case f := <-p.do:
|
|
p.Lock()
|
|
if p.inprogress {
|
|
p.Unlock()
|
|
continue
|
|
}
|
|
p.inprogress = true
|
|
p.Unlock()
|
|
|
|
// Passed the lock. Now run f for as long it returns false. If a true is returned
|
|
// we return from the goroutine and we can accept another Func to run.
|
|
go func() {
|
|
for {
|
|
if err := f(); err == nil {
|
|
break
|
|
}
|
|
// TODO(miek): little bit of exponential backoff here?
|
|
time.Sleep(interval)
|
|
}
|
|
p.Lock()
|
|
p.inprogress = false
|
|
p.Unlock()
|
|
}()
|
|
}
|
|
}
|
|
}
|