1
0
Fork 0

Add passive health checks

This commit is contained in:
Nelson Isioma 2025-08-21 10:40:06 +01:00 committed by GitHub
parent c20802b07e
commit fc0fac8543
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 696 additions and 6 deletions

View file

@ -341,7 +341,7 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName
var lb serverBalancer
switch service.Strategy {
// Here we are handling the empty value to comply with providers that are not applying defaults (e.g. REST provider)
// TODO: remove this when all providers apply default values.
// TODO: remove this empty check when all providers apply default values.
case dynamic.BalancerStrategyWRR, "":
lb = wrr.New(service.Sticky, service.HealthCheck != nil)
case dynamic.BalancerStrategyP2C:
@ -350,6 +350,17 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName
return nil, fmt.Errorf("unsupported load-balancer strategy %q", service.Strategy)
}
var passiveHealthChecker *healthcheck.PassiveServiceHealthChecker
if service.PassiveHealthCheck != nil {
passiveHealthChecker = healthcheck.NewPassiveHealthChecker(
serviceName,
lb,
service.PassiveHealthCheck.MaxFailedAttempts,
service.PassiveHealthCheck.FailureWindow,
service.HealthCheck != nil,
m.observabilityMgr.MetricsRegistry())
}
healthCheckTargets := make(map[string]*url.URL)
for i, server := range shuffle(service.Servers, m.rand) {
@ -368,6 +379,11 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName
return nil, fmt.Errorf("error building proxy for server URL %s: %w", server.URL, err)
}
if passiveHealthChecker != nil {
// If passive health check is enabled, we wrap the proxy with the passive health checker.
proxy = passiveHealthChecker.WrapHandler(ctx, proxy, target.String())
}
// The retry wrapping must be done just before the proxy handler,
// to make sure that the retry will not be triggered/disabled by
// middlewares in the chain.

View file

@ -10,9 +10,11 @@ import (
"net/textproto"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/config/runtime"
"github.com/traefik/traefik/v3/pkg/proxy/httputil"
@ -67,6 +69,19 @@ func TestGetLoadBalancer(t *testing.T) {
fwd: &forwarderMock{},
expectError: false,
},
{
desc: "Succeeds when passive health checker is set",
serviceName: "test",
service: &dynamic.ServersLoadBalancer{
Strategy: dynamic.BalancerStrategyWRR,
PassiveHealthCheck: &dynamic.PassiveServerHealthCheck{
FailureWindow: ptypes.Duration(30 * time.Second),
MaxFailedAttempts: 3,
},
},
fwd: &forwarderMock{},
expectError: false,
},
}
for _, test := range testCases {