Documentation
¶
Overview ¶
Package health provides comprehensive health check functionality for Forge microservices.
The health package implements Kubernetes-compatible health checks with support for both liveness and readiness probes. It provides concurrent health check execution, configurable timeouts, and detailed status reporting.
Health Check Types ¶
The package supports two types of health checks:
- Liveness: Indicates whether the application is alive and responding
- Readiness: Indicates whether the application is ready to serve traffic
Basic Usage ¶
Implement the Check interface for your dependencies:
type DatabaseCheck struct {
db *sql.DB
}
func (c *DatabaseCheck) Name() string {
return "database"
}
func (c *DatabaseCheck) Liveness(ctx context.Context) error {
return c.db.PingContext(ctx)
}
func (c *DatabaseCheck) Readiness(ctx context.Context) error {
// More comprehensive readiness check
if err := c.db.PingContext(ctx); err != nil {
return err
}
// Check if migrations are up to date, etc.
return nil
}
Register checks with the health registry:
registry := health.NewRegistry(logger)
config := health.DefaultCheckConfig("database")
registry.Register(&DatabaseCheck{db: db}, config)
HTTP Endpoints ¶
The framework automatically exposes health endpoints:
- /health: Combined liveness and readiness status
- /health/live: Liveness probe endpoint
- /health/ready: Readiness probe endpoint
Concurrent Execution ¶
All health checks are executed concurrently with proper timeout handling. Failed non-required checks don't affect overall service health.
Index ¶
- type AlwaysHealthyCheck
- type AlwaysUnhealthyCheck
- type BasicCheck
- type Check
- type CheckConfig
- type CheckResult
- type HealthySummary
- type Logger
- type NoopLogger
- type Registry
- func (r *Registry) CheckConfig(name string) (CheckConfig, bool)
- func (r *Registry) CheckHealth(ctx context.Context) Report
- func (r *Registry) CheckLiveness(ctx context.Context) Report
- func (r *Registry) CheckReadiness(ctx context.Context) Report
- func (r *Registry) IsReady() bool
- func (r *Registry) MustRegister(check Check, config CheckConfig)
- func (r *Registry) Register(check Check, config CheckConfig) error
- func (r *Registry) RegisteredChecks() []string
- func (r *Registry) SetReady(ready bool)
- func (r *Registry) Start(ctx context.Context) error
- func (r *Registry) Stop(ctx context.Context) error
- func (r *Registry) Unregister(name string)
- type Report
- func (h Report) FailedChecks() []CheckResult
- func (h Report) HTTPStatus() int
- func (h Report) HealthySummary() HealthySummary
- func (h Report) IsHealthy() bool
- func (h Report) IsLive() bool
- func (h Report) IsReady() bool
- func (h Report) JSON() ([]byte, error)
- func (h Report) Redacted() Report
- func (h Report) RequiredFailedChecks() []CheckResult
- func (h Report) String() string
- func (h Report) WithService(service string) Report
- func (h Report) WithUptime(uptime time.Duration) Report
- func (h Report) WithVersion(version string) Report
- type Status
- type StatusResponse
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AlwaysHealthyCheck ¶
type AlwaysHealthyCheck struct {
// contains filtered or unexported fields
}
AlwaysHealthyCheck is a check that always reports healthy status. Useful for testing or as a placeholder.
func NewAlwaysHealthyCheck ¶
func NewAlwaysHealthyCheck(name string) *AlwaysHealthyCheck
NewAlwaysHealthyCheck creates a check that always reports healthy.
func (*AlwaysHealthyCheck) Liveness ¶
func (c *AlwaysHealthyCheck) Liveness(ctx context.Context) error
Liveness always returns nil (healthy).
func (*AlwaysHealthyCheck) Name ¶
func (c *AlwaysHealthyCheck) Name() string
Name returns the name of the check.
type AlwaysUnhealthyCheck ¶
type AlwaysUnhealthyCheck struct {
// contains filtered or unexported fields
}
AlwaysUnhealthyCheck is a check that always reports unhealthy status. Useful for testing failure scenarios.
func NewAlwaysUnhealthyCheck ¶
func NewAlwaysUnhealthyCheck(name string, err error) *AlwaysUnhealthyCheck
NewAlwaysUnhealthyCheck creates a check that always reports unhealthy.
func (*AlwaysUnhealthyCheck) Liveness ¶
func (c *AlwaysUnhealthyCheck) Liveness(ctx context.Context) error
Liveness always returns an error (unhealthy).
func (*AlwaysUnhealthyCheck) Name ¶
func (c *AlwaysUnhealthyCheck) Name() string
Name returns the name of the check.
type BasicCheck ¶
type BasicCheck struct {
// contains filtered or unexported fields
}
BasicCheck provides a simple implementation of Check interface.
func NewBasicCheck ¶
func NewBasicCheck(config CheckConfig, liveness, readiness func(ctx context.Context) error) *BasicCheck
NewBasicCheck creates a new BasicCheck.
func (*BasicCheck) Config ¶
func (c *BasicCheck) Config() CheckConfig
Config returns the check configuration.
func (*BasicCheck) Liveness ¶
func (c *BasicCheck) Liveness(ctx context.Context) error
Liveness performs the liveness check.
func (*BasicCheck) Name ¶
func (c *BasicCheck) Name() string
Name returns the name of the health check.
type Check ¶
type Check interface {
// Name returns a unique name for this health check.
Name() string
// Liveness performs a liveness check. This should be a fast, lightweight
// check that indicates whether the dependency is alive and responding.
// A failed liveness check typically indicates a need for service restart.
Liveness(ctx context.Context) error
// Readiness performs a readiness check. This can be more comprehensive
// than liveness and indicates whether the dependency is ready to serve
// requests. A failed readiness check should result in the service being
// marked as not ready (but still alive).
Readiness(ctx context.Context) error
}
Check represents a health check that can be performed on a service dependency. Each check supports both liveness (is the dependency alive) and readiness (is the dependency ready to serve requests) semantics.
Implementations should be lightweight and fast, especially for liveness checks. Readiness checks can be more comprehensive but should still complete within the configured timeout.
Health checks are executed concurrently by the health registry, so implementations must be thread-safe.
type CheckConfig ¶
type CheckConfig struct {
// Name is the unique name of the health check
Name string
// Required indicates whether this check is required for readiness.
// If true, the service will not be marked as ready until this check passes.
Required bool
// Timeout is the maximum time to wait for the health check to complete.
Timeout time.Duration
// Interval is how often to perform the check (for periodic checks).
Interval time.Duration
// InitialDelay is how long to wait before performing the first check.
InitialDelay time.Duration
}
CheckConfig contains common configuration for health checks. Use DefaultCheckConfig() as a starting point and customize as needed.
The Required field determines whether a failed check affects overall service health:
- Required=true: Service is unhealthy if this check fails
- Required=false: Check failure is logged but doesn't affect service health
Timeout applies to both liveness and readiness checks for this specific check. The health registry also enforces an overall timeout for all checks combined.
func DefaultCheckConfig ¶
func DefaultCheckConfig(name string) CheckConfig
DefaultCheckConfig returns a CheckConfig with sensible defaults. All checks are marked as required by default with a 5-second timeout and 30-second check interval for periodic monitoring.
Customize the returned config as needed:
config := health.DefaultCheckConfig("database")
config.Required = false // Make non-critical
config.Timeout = 10 * time.Second // Longer timeout
type CheckResult ¶
type CheckResult struct {
Name string `json:"name"`
Status Status `json:"status"`
Message string `json:"message,omitempty"`
Error string `json:"error,omitempty"`
Duration string `json:"duration"`
Timestamp time.Time `json:"timestamp"`
Required bool `json:"required"`
}
CheckResult represents the result of executing a health check.
func NewCheckResult ¶
NewCheckResult creates a new CheckResult.
func (CheckResult) IsHealthy ¶
func (r CheckResult) IsHealthy() bool
IsHealthy returns true if the check result indicates a healthy status.
func (CheckResult) Redacted ¶ added in v0.3.0
func (r CheckResult) Redacted() CheckResult
Redacted returns a copy of the CheckResult with the raw Error detail removed. Error strings from dependency checks (e.g. database or cache connectivity failures) can embed internal topology such as hostnames, IPs, and ports, so they must not be exposed over unauthenticated interfaces like the public HTTP health endpoints. The check name and Status remain, which is all an external caller needs; the full detail is still available internally (e.g. to the background runner's logs).
type HealthySummary ¶
type HealthySummary struct {
Total int `json:"total"`
Healthy int `json:"healthy"`
Unhealthy int `json:"unhealthy"`
Required int `json:"required"`
}
HealthySummary provides a summary of healthy vs unhealthy checks.
type Logger ¶
type Logger interface {
Debug(msg string, fields ...any)
Info(msg string, fields ...any)
Warn(msg string, fields ...any)
Error(msg string, fields ...any)
}
Logger interface for health check logging.
type NoopLogger ¶
type NoopLogger struct{}
NoopLogger is a logger that does nothing.
func (NoopLogger) Debug ¶
func (NoopLogger) Debug(msg string, fields ...any)
Debug discards a debug-level message.
func (NoopLogger) Error ¶
func (NoopLogger) Error(msg string, fields ...any)
Error discards an error-level message.
func (NoopLogger) Info ¶
func (NoopLogger) Info(msg string, fields ...any)
Info discards an info-level message.
func (NoopLogger) Warn ¶
func (NoopLogger) Warn(msg string, fields ...any)
Warn discards a warning-level message.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry manages a collection of health checks and provides methods to check the overall health status of a service.
By default, Registry computes results live on every call (the original behavior, and what unit tests and direct library use still get). Calling Start runs checks in the background on their configured Interval and serves cached results instead, so a probe read never blocks on a slow or hanging dependency check.
func NewRegistry ¶
NewRegistry creates a new health check registry.
func (*Registry) CheckConfig ¶ added in v0.3.0
func (r *Registry) CheckConfig(name string) (CheckConfig, bool)
CheckConfig returns the configuration for a specific check.
func (*Registry) CheckHealth ¶
CheckHealth performs both liveness and readiness checks and returns combined results.
When the background runner is active, both sides are built from a single cached snapshot (one lock acquisition) rather than two serialized live rounds of every check.
func (*Registry) CheckLiveness ¶
CheckLiveness performs liveness checks on all registered health checks.
If the background runner is active, this serves the latest cached results instead of computing them live.
func (*Registry) CheckReadiness ¶
CheckReadiness performs readiness checks on all registered health checks.
If the background runner is active, this serves the latest cached results instead of computing them live.
func (*Registry) MustRegister ¶
func (r *Registry) MustRegister(check Check, config CheckConfig)
MustRegister registers a health check and panics if registration fails.
func (*Registry) Register ¶
func (r *Registry) Register(check Check, config CheckConfig) error
Register registers a health check with the registry.
If the background runner is already started (see Start), the new check is picked up immediately and scheduled on its own goroutine so that checks registered after startup still get background execution.
func (*Registry) RegisteredChecks ¶ added in v0.3.0
RegisteredChecks returns the names of all registered checks.
func (*Registry) SetReady ¶
SetReady marks the service as ready. This affects the overall readiness status.
func (*Registry) Start ¶ added in v0.3.0
Start launches the background check runner: one goroutine per registered check that waits its CheckConfig.InitialDelay, runs an immediate round, and then re-runs on CheckConfig.Interval until Stop is called or ctx is done. Once started, CheckLiveness/CheckReadiness/CheckHealth serve the cached results from these rounds instead of computing live, so a probe read is never blocked by a slow or hanging dependency.
Start is not safe to call twice without an intervening Stop.
func (*Registry) Stop ¶ added in v0.3.0
Stop cancels all background runner goroutines and waits for them to exit, or for ctx to be done, whichever comes first. It is safe to call even if Start was never called. After Stop returns (with a nil error), no runner goroutines remain.
func (*Registry) Unregister ¶
Unregister removes a health check from the registry.
If the background runner is active, the check's goroutine notices the removal on its next tick (or initial round) and exits on its own; there is nothing further to clean up here.
type Report ¶ added in v0.3.0
type Report struct {
Status Status `json:"status"`
Message string `json:"message,omitempty"`
Timestamp time.Time `json:"timestamp"`
Details map[string]CheckResult `json:"details,omitempty"`
Service string `json:"service,omitempty"`
Version string `json:"version,omitempty"`
Uptime string `json:"uptime,omitempty"`
}
Report represents the overall health status of a service, including aggregated results from individual health checks.
func NewHealthyReport ¶ added in v0.3.0
NewHealthyReport creates a new healthy status with the given message.
func NewUnhealthyReport ¶ added in v0.3.0
NewUnhealthyReport creates a new unhealthy status with the given message.
func NewUnknownReport ¶ added in v0.3.0
NewUnknownReport creates a new unknown status with the given message.
func (Report) FailedChecks ¶ added in v0.3.0
func (h Report) FailedChecks() []CheckResult
FailedChecks returns a slice of check results that failed.
func (Report) HTTPStatus ¶ added in v0.3.0
HTTPStatus returns the appropriate HTTP status code for this health status.
func (Report) HealthySummary ¶ added in v0.3.0
func (h Report) HealthySummary() HealthySummary
HealthySummary returns a summary of the health check results.
func (Report) IsLive ¶ added in v0.3.0
IsLive returns true if the status indicates the service is alive. For liveness checks, we consider the service live if it's not explicitly unhealthy.
func (Report) IsReady ¶ added in v0.3.0
IsReady returns true if the status indicates the service is ready to serve requests. This is an alias for IsHealthy for readiness checks.
func (Report) Redacted ¶ added in v0.3.0
Redacted returns a copy of the Report safe for exposure over unauthenticated interfaces such as the public HTTP health endpoints. Every entry in Details has its raw error detail stripped via CheckResult.Redacted, while the overall Status, Message, and per-check name/status/duration/required metadata are preserved.
func (Report) RequiredFailedChecks ¶ added in v0.3.0
func (h Report) RequiredFailedChecks() []CheckResult
RequiredFailedChecks returns a slice of required check results that failed.
func (Report) WithService ¶ added in v0.3.0
WithService sets the service name on the health status.
func (Report) WithUptime ¶ added in v0.3.0
WithUptime sets the uptime on the health status.
func (Report) WithVersion ¶ added in v0.3.0
WithVersion sets the version on the health status.
type StatusResponse ¶
type StatusResponse struct {
Status Status `json:"status"`
Message string `json:"message,omitempty"`
}
StatusResponse is a simplified response for basic health checks.
func NewStatusResponse ¶
func NewStatusResponse(status Report) StatusResponse
NewStatusResponse creates a new status response from a health status.
func (StatusResponse) HTTPStatus ¶
func (s StatusResponse) HTTPStatus() int
HTTPStatus returns the appropriate HTTP status code.
func (StatusResponse) JSON ¶
func (s StatusResponse) JSON() ([]byte, error)
JSON returns the JSON representation of the status response.