mirror of
https://github.com/coredns/coredns.git
synced 2026-10-26 04:05:43 -04:00
plugin/forward: add startup health checks with start_failed (#8663)
* plugin/forward: add startup health checks with start_failed Signed-off-by: houyuwushang <180804215+houyuwushang@users.noreply.github.com> * test: separate CoreDNS and third-party imports Signed-off-by: houyuwushang <180804215+houyuwushang@users.noreply.github.com> --------- Signed-off-by: houyuwushang <180804215+houyuwushang@users.noreply.github.com>
This commit is contained in:
@@ -521,6 +521,7 @@ func TestDoQHealthCheck(t *testing.T) {
|
||||
})
|
||||
|
||||
p := NewProxy("TestDoQHealth", server.addr(), transport.QUIC)
|
||||
p.initiallyDown.Store(true)
|
||||
p.SetTLSConfig(clientTLS)
|
||||
defer p.Stop()
|
||||
hc := p.GetHealthchecker()
|
||||
@@ -529,6 +530,9 @@ func TestDoQHealthCheck(t *testing.T) {
|
||||
if err := hc.Check(p); err != nil {
|
||||
t.Fatalf("health check failed: %v", err)
|
||||
}
|
||||
if p.Down(2) {
|
||||
t.Error("successful QUIC health check did not clear startup failure")
|
||||
}
|
||||
msg := <-query
|
||||
if len(msg.Question) != 1 || msg.Question[0].Name != "health.example." || msg.Question[0].Qtype != dns.TypeNS {
|
||||
t.Fatalf("unexpected health query: %v", msg.Question)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/doh"
|
||||
@@ -130,7 +129,7 @@ func (h *doqHc) Check(p *Proxy) error {
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.StoreUint32(&p.fails, 0)
|
||||
p.resetFails()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -219,7 +218,7 @@ func (h *dnsHc) Check(p *Proxy) error {
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.StoreUint32(&p.fails, 0)
|
||||
p.resetFails()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -293,7 +292,7 @@ func (h *dohHc) Check(p *Proxy) error {
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.StoreUint32(&p.fails, 0)
|
||||
p.resetFails()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,15 @@ func TestHealth(t *testing.T) {
|
||||
hc.SetWriteTimeout(10 * time.Millisecond)
|
||||
|
||||
p := NewProxy("TestHealth", s.Addr, transport.DNS)
|
||||
p.initiallyDown.Store(true)
|
||||
p.readTimeout = 10 * time.Millisecond
|
||||
err := hc.Check(p)
|
||||
if err != nil {
|
||||
t.Errorf("check failed: %v", err)
|
||||
}
|
||||
if p.Down(2) {
|
||||
t.Error("successful DNS health check did not clear startup failure")
|
||||
}
|
||||
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
i1 := atomic.LoadUint32(&i)
|
||||
@@ -110,11 +114,15 @@ func TestHealthHTTPS(t *testing.T) {
|
||||
hc.SetWriteTimeout(1 * time.Second)
|
||||
|
||||
p := NewProxy("TestHealthHTTPS", s.URL, transport.HTTPS)
|
||||
p.initiallyDown.Store(true)
|
||||
p.readTimeout = 10 * time.Millisecond
|
||||
err := hc.Check(p)
|
||||
if err != nil {
|
||||
t.Fatalf("check failed: %v", err)
|
||||
}
|
||||
if p.Down(2) {
|
||||
t.Error("successful HTTPS health check did not clear startup failure")
|
||||
}
|
||||
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
i1 := atomic.LoadUint32(&i)
|
||||
|
||||
@@ -15,9 +15,10 @@ import (
|
||||
|
||||
// Proxy defines an upstream host.
|
||||
type Proxy struct {
|
||||
fails uint32
|
||||
addr string
|
||||
proxyName string
|
||||
fails uint32
|
||||
initiallyDown atomic.Bool
|
||||
addr string
|
||||
proxyName string
|
||||
|
||||
transport *Transport
|
||||
doq *doqTransport
|
||||
@@ -136,14 +137,28 @@ func (p *Proxy) Healthcheck() {
|
||||
})
|
||||
}
|
||||
|
||||
// Down returns true if this proxy is down, i.e. has *more* fails than maxfails.
|
||||
// StartFailed marks the proxy down until its first successful health check and
|
||||
// starts probing immediately. Start must be called first to set the probe interval.
|
||||
func (p *Proxy) StartFailed() {
|
||||
p.initiallyDown.Store(true)
|
||||
p.Healthcheck()
|
||||
}
|
||||
|
||||
// Down reports whether the proxy is awaiting its first successful startup check
|
||||
// or has more failures than maxfails. A zero maxfails disables both checks.
|
||||
func (p *Proxy) Down(maxfails uint32) bool {
|
||||
if maxfails == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
fails := atomic.LoadUint32(&p.fails)
|
||||
return fails > maxfails
|
||||
return p.initiallyDown.Load() || fails > maxfails
|
||||
}
|
||||
|
||||
// resetFails makes the proxy available after a successful health check.
|
||||
func (p *Proxy) resetFails() {
|
||||
atomic.StoreUint32(&p.fails, 0)
|
||||
p.initiallyDown.Store(false)
|
||||
}
|
||||
|
||||
// Stop stops health checking and closes the DoQ transport, when configured.
|
||||
|
||||
Reference in New Issue
Block a user