proxy-pool/internal/controller/health/policy.go
youfak 65aee12d51
Some checks are pending
ci / proto (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
ci / integration (push) Waiting to run
feat: wire checker observations into controller
2026-07-31 18:25:07 +08:00

66 lines
2.0 KiB
Go

package health
import (
"context"
"errors"
"time"
"proxy-pool/internal/config"
"proxy-pool/internal/domain/activitypool"
healthDomain "proxy-pool/internal/domain/health"
)
var (
ErrInvalidPolicyResolver = errors.New("invalid health policy resolver")
ErrUnconfiguredUpstream = errors.New("health observation references an unconfigured upstream")
)
// ConfigurationSource returns a detached, validated configuration snapshot.
// config.Store implements this interface without exposing its publication
// mechanism to the health package.
type ConfigurationSource interface {
Current() *config.Config
}
// NewConfiguredFailureThresholdResolver resolves the policy against the
// proxy's authoritative upstream at apply time. It keeps Checker input from
// choosing its own failure threshold and follows Controller config reloads.
func NewConfiguredFailureThresholdResolver(
configuration ConfigurationSource,
proxies activitypool.ProxyUpstreamReader,
now func() time.Time,
) (FailureThresholdResolver, error) {
if nilInterface(configuration) || nilInterface(proxies) || now == nil {
return nil, ErrInvalidPolicyResolver
}
return func(ctx context.Context, observation healthDomain.Observation) (int, error) {
if ctx == nil {
return 0, ErrInvalidPolicyResolver
}
if err := ctx.Err(); err != nil {
return 0, err
}
current := configuration.Current()
if current == nil {
return 0, ErrInvalidPolicyResolver
}
currentTime := now()
if currentTime.IsZero() {
return 0, ErrInvalidPolicyResolver
}
upstreamID, err := proxies.UpstreamForProxy(ctx, observation.ProxyID, currentTime.UTC())
if err != nil {
return 0, err
}
upstream, exists := current.Upstreams[upstreamID]
if !exists || !upstream.Enabled {
return 0, ErrUnconfiguredUpstream
}
check := config.EffectiveCheck(current.Defaults.Check, upstream.Check)
if check.MaxConsecutiveFailures <= 0 {
return 0, ErrInvalidThreshold
}
return check.MaxConsecutiveFailures, nil
}, nil
}