Replace balancer panic with deferred error; test HealthChecker

A malformed endpoint URL panicked inside Transport, crashing the host app
(often at startup from external config). Capture the parse error and surface
it from the transport on first use instead. Add the previously untested
HealthChecker coverage (initial probe, recovery, Stop termination, unknown
endpoint), raising balancer coverage from ~41% to ~87%. Default the health
probe path to /healthz to match this library's own server.
This commit is contained in:
2026-05-23 13:47:33 +03:00
parent b07d487e63
commit 01478be0dc
4 changed files with 134 additions and 3 deletions

View File

@@ -55,12 +55,19 @@ func Transport(endpoints []Endpoint, opts ...Option) (middleware.Middleware, *Cl
opt(o)
}
// Pre-parse endpoint URLs once at construction time.
// Pre-parse endpoint URLs once at construction time. A malformed URL is a
// configuration error: rather than panicking (which would crash the host
// application, often at startup from external config), we capture the
// error and surface it from the transport on first use.
parsed := make(map[string]*url.URL, len(endpoints))
var parseErr error
for _, ep := range endpoints {
u, err := url.Parse(ep.URL)
if err != nil {
panic(fmt.Sprintf("balancer: invalid endpoint URL %q: %v", ep.URL, err))
if parseErr == nil {
parseErr = fmt.Errorf("balancer: invalid endpoint URL %q: %w", ep.URL, err)
}
continue
}
parsed[ep.URL] = u
}
@@ -73,6 +80,10 @@ func Transport(endpoints []Endpoint, opts ...Option) (middleware.Middleware, *Cl
return func(next http.RoundTripper) http.RoundTripper {
return middleware.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
if parseErr != nil {
return nil, parseErr
}
healthy := endpoints
if o.healthChecker != nil {
healthy = o.healthChecker.Healthy(endpoints)