Documentation
¶
Overview ¶
Package health answers the two questions an orchestrator asks, which are not the same question.
liveness — is this process broken beyond recovery? Restart me if not. readiness — can this process serve traffic right now? Route to me if so.
Conflating them is the classic Kubernetes outage: a liveness probe that pings the database means a database blip restarts every replica simultaneously, turning a recoverable dependency failure into a total one. So Live here checks NOTHING but the process being able to answer, and Ready is where dependencies belong.
Example ¶
Severity is the decision that matters. An optional dependency degrades the service; it does not take it out of rotation.
package main
import (
"context"
"errors"
"fmt"
"github.com/IncepTools/go/src/web/health"
)
func main() {
r := health.New("shop", "1.4.2")
r.Register(
health.Of("database", health.Critical, func(context.Context) error { return nil }),
health.Of("cache", health.Optional, func(context.Context) error {
return errors.New("connection refused")
}),
)
report := r.Run(context.Background())
fmt.Println("overall:", report.Status)
fmt.Println("database:", report.Checks["database"].Status)
fmt.Println("cache:", report.Checks["cache"].Status)
}
Output: overall: DEGRADED database: UP cache: DEGRADED
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DetailHandler ¶
DetailHandler returns the full report with per-check latency, always 200. It is for humans and dashboards, not for probes.
Put it behind authentication: the check names and messages describe your internal topology.
func LiveHandler ¶
LiveHandler answers liveness. It checks nothing: if this code runs, the process is alive. Point the liveness probe here and nowhere else.
func ReadyHandler ¶
ReadyHandler answers readiness: 200 while the service can serve, 503 once a critical dependency is down. A DEGRADED report still returns 200 — that is what Optional means.
Types ¶
type Check ¶
type Check struct {
Name string `json:"name"`
Status Status `json:"status"`
Message string `json:"message,omitempty"`
LatencyMS int64 `json:"latencyMs"`
Details map[string]any `json:"details,omitempty"`
Severity string `json:"severity,omitempty"`
}
Check is one dependency's result.
type Checker ¶
Checker probes one dependency.
An implementation MUST honour ctx: the registry gives each check a deadline, and a check that ignores it holds up the whole report — which is how a readiness endpoint ends up timing out and taking every replica out of rotation at once.
type Registry ¶
type Registry struct {
// Timeout bounds each individual check. Defaults to 2s.
Timeout time.Duration
Service string
Version string
// contains filtered or unexported fields
}
Registry holds the checks a service runs. The zero value is usable.
func (*Registry) Run ¶
Run probes every dependency CONCURRENTLY and aggregates.
Concurrently because sequentially is how a readiness endpoint with six two-second checks takes twelve seconds and gets killed by the probe timeout it was meant to satisfy.
Example (CriticalFailure) ¶
A critical dependency failing is what takes the service out of rotation, and only that.
package main
import (
"context"
"errors"
"fmt"
"github.com/IncepTools/go/src/web/health"
)
func main() {
r := health.New("shop", "1.4.2")
r.Register(health.Of("database", health.Critical,
func(context.Context) error { return errors.New("connection refused") }))
fmt.Println(r.Run(context.Background()).Status)
}
Output: DOWN
type Report ¶
type Report struct {
Status Status `json:"status"`
Service string `json:"service,omitempty"`
Version string `json:"version,omitempty"`
Uptime string `json:"uptime,omitempty"`
Checks map[string]Check `json:"checks,omitempty"`
}
Report is the aggregate.
type Severity ¶
type Severity int
Severity says what a failing check means for the service as a whole.
const ( // Critical means this failing takes the service out of rotation. Critical Severity = iota // Optional means this failing degrades the service but it keeps serving. // // Most caches, most third-party APIs and every analytics sink belong // here. A service that reports itself DOWN because an analytics endpoint // is slow has made an outage out of a nuisance. Optional )
type Status ¶
type Status string
Status is the outcome of a check.
const ( // StatusUp means working. StatusUp Status = "UP" // StatusDegraded means working with reduced capability — a cache that is // down but is only a cache. A degraded service still takes traffic. StatusDegraded Status = "DEGRADED" // StatusDown means not working. A down service is removed from the load // balancer. StatusDown Status = "DOWN" )