feat(health)!: promote to v1.0.0 — configurable check timeout via NewHandlerWithConfig

Add Config struct and NewHandlerWithConfig(logger, cfg, checks...) constructor.
Config.CheckTimeout sets the per-request deadline for all health checks; zero
value defaults to 5 seconds. NewHandler remains unchanged as a backward-compatible
wrapper. API committed as stable.
This commit is contained in:
2026-05-11 19:05:27 -06:00
parent e1b6b7ddd7
commit 8d6930b087
3 changed files with 67 additions and 6 deletions

View File

@@ -48,23 +48,44 @@ type Response struct {
Components map[string]ComponentStatus `json:"components"`
}
type handler struct {
logger Logger
checks []Checkable
// Config configures a health handler.
// The zero value is valid: 5-second check timeout.
type Config struct {
// CheckTimeout is the per-request deadline for all health checks.
// Defaults to 5 seconds when zero.
CheckTimeout time.Duration
}
// NewHandler returns an http.Handler for the health endpoint.
const defaultCheckTimeout = 5 * time.Second
type handler struct {
logger Logger
checks []Checkable
timeout time.Duration
}
// NewHandler returns an http.Handler for the health endpoint with default configuration.
// Runs all checks concurrently with a 5-second timeout.
// Returns 200 (UP/DEGRADED) or 503 (DOWN).
func NewHandler(logger Logger, checks ...Checkable) http.Handler {
return &handler{logger: logger, checks: checks}
return NewHandlerWithConfig(logger, Config{}, checks...)
}
// NewHandlerWithConfig returns an http.Handler configured by cfg.
// If cfg.CheckTimeout is zero, a 5-second default is used.
func NewHandlerWithConfig(logger Logger, cfg Config, checks ...Checkable) http.Handler {
timeout := cfg.CheckTimeout
if timeout == 0 {
timeout = defaultCheckTimeout
}
return &handler{logger: logger, checks: checks, timeout: timeout}
}
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logger := h.logger.WithContext(r.Context())
logger.Debug("health: running checks")
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
ctx, cancel := context.WithTimeout(r.Context(), h.timeout)
defer cancel()
type result struct {