health

package
v1.3.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package health provides health checking utilities for nSelf services.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ContainerName added in v1.3.4

func ContainerName(projectName, service string) string

ContainerName returns the Docker container name for a given service. nSelf compose uses the pattern {ProjectName}_{service} with hyphens replaced by underscores in the service portion.

Exported so other packages that need to shell out to a specific nSelf container (e.g. internal/doctor's --deep and hardening checks) compute the name the same way instead of hardcoding it — see CLI PRI lessons.md, "container name derivation" (the dogfood Postgres/nginx checks were hardcoded to nself_postgres/nself_nginx and could never pass on a project with a custom PROJECT_NAME).

func HasuraHealthzHandler added in v1.1.6

func HasuraHealthzHandler(cfg HasuraHealthzConfig) http.HandlerFunc

HasuraHealthzHandler returns an http.HandlerFunc that probes Hasura asynchronously with a configurable timeout and returns the appropriate three-state response.

cfg controls the Hasura URL and timeout threshold. Use HasuraHealthzConfigFromEnv() for production; inject custom values in tests.

func SaveHistory

func SaveHistory(report *HealthReport, historyDir string) error

SaveHistory appends a single HealthReport as one JSON line to {historyDir}/history.jsonl. The directory is created if it does not exist.

func WatchHealth

func WatchHealth(ctx context.Context, cfg *config.Config, workdir string, interval time.Duration) (<-chan *HealthReport, error)

WatchHealth starts a continuous monitoring loop that sends a fresh HealthReport on the returned channel at the given interval. The loop exits when ctx is cancelled; the channel is closed on exit.

Types

type DockerClient

type DockerClient interface {
	// ContainerList returns running containers, optionally filtered by label.
	ContainerList(ctx context.Context, filters map[string]string) ([]RestartContainer, error)
	// ContainerInspect returns detailed info for a single container by ID or name.
	ContainerInspect(ctx context.Context, id string) (RestartContainerInfo, error)
	// ContainerRestart restarts a container. timeout is in seconds; 0 uses Docker default.
	ContainerRestart(ctx context.Context, id string, timeout int) error
}

DockerClient abstracts the Docker operations needed by Restarter for testability.

type HasuraHealthzConfig added in v1.1.6

type HasuraHealthzConfig struct {
	// HasuraURL is the URL to probe for Hasura liveness.
	HasuraURL string

	// TimeoutMS is the threshold in milliseconds. A Hasura response slower than
	// this is reported as "degraded" rather than "down".
	TimeoutMS int
}

HasuraHealthzConfig holds runtime configuration for the Hasura health check. Read from env at handler construction time; immutable during serving.

func HasuraHealthzConfigFromEnv added in v1.1.6

func HasuraHealthzConfigFromEnv() HasuraHealthzConfig

HasuraHealthzConfigFromEnv reads HEALTHZ_HASURA_TIMEOUT_MS and HEALTHZ_HASURA_URL from the environment, applying defaults for any missing or invalid values.

type HealthReport

type HealthReport struct {
	Timestamp time.Time      `json:"timestamp"`
	Results   []HealthResult `json:"results"`
	Healthy   int            `json:"healthy"`
	Unhealthy int            `json:"unhealthy"`
	Total     int            `json:"total"`
}

HealthReport aggregates the results of checking all services.

func GetHistory

func GetHistory(historyDir string, limit int) ([]HealthReport, error)

GetHistory reads the last limit HealthReport entries from {historyDir}/history.jsonl. If the file does not exist an empty slice is returned. When limit <= 0 all entries are returned.

func RunAllChecks

func RunAllChecks(ctx context.Context, cfg *config.Config, workdir string) (*HealthReport, error)

RunAllChecks queries Docker health status for every enabled service and returns a consolidated HealthReport.

It uses docker compose ps --format json (via the compose manifest) to query health status directly from the Docker Compose project, which is immune to container name guessing issues. It falls back to per-container docker inspect for any service not reported by compose ps.

type HealthResult

type HealthResult struct {
	Service  string        `json:"service"`
	Status   string        `json:"status"` // healthy, unhealthy, starting, none, not_found, error
	Duration time.Duration `json:"duration"`
	Details  string        `json:"details"`
}

HealthResult holds the outcome of a single service health check.

func CheckEndpoint

func CheckEndpoint(ctx context.Context, url string) (*HealthResult, error)

CheckEndpoint performs an HTTP GET against the given URL and reports whether it returned a 2xx status code. The request uses a 10-second timeout by default, or inherits the context deadline if shorter.

func CheckService

func CheckService(ctx context.Context, service string) (*HealthResult, error)

CheckService checks the Docker health status of a single named service. The service name should match the docker-compose service name (e.g. "postgres", "hasura", "redis") or a full container name.

func ProbeMailpit added in v1.0.11

func ProbeMailpit(ctx context.Context, host string, port int) *HealthResult

ProbeMailpit performs an HTTP GET to /api/v1/info on the given host:port. Mailpit returns {"Version":"..."} when healthy.

func ProbeMeiliSearch added in v1.0.11

func ProbeMeiliSearch(ctx context.Context, host string, port int) *HealthResult

ProbeMeiliSearch performs an HTTP GET to /health on the given host:port. MeiliSearch returns {"status":"available"} when healthy.

func ProbeMinIO added in v1.0.11

func ProbeMinIO(ctx context.Context, host string, port int) *HealthResult

ProbeMinIO performs an HTTP GET to /minio/health/live on the given host:port. MinIO returns HTTP 200 when healthy.

func ProbeNginxHTTP added in v1.0.11

func ProbeNginxHTTP(ctx context.Context, host string, port int) *HealthResult

ProbeNginxHTTP performs an HTTP GET on port 80 of the given host and considers any HTTP response (including redirects) as healthy.

func ProbeRedis added in v1.0.11

func ProbeRedis(ctx context.Context, containerID, password string) *HealthResult

ProbeRedis runs a Redis PING via docker exec and returns healthy if the response is "PONG". The containerID argument should be the running container name or ID (e.g. "myproject_redis").

func (HealthResult) OK added in v1.3.4

func (r HealthResult) OK() bool

OK is the single accept-predicate for whether a HealthResult counts as healthy. A container with no Docker healthcheck configured reports "running" rather than "healthy" (see resolveServiceHealth's comment on buildComposeHealthMap) and is intentionally accepted here.

Both aggregate and per-service verdicts MUST call this method — the aggregate count in RunAllChecks, every per-service printer in cmd/commands/start_health.go, and the CI readiness gate in waitCIReady. Do not reintroduce an inline `Status == "healthy"` (or `!=`) comparison anywhere a HealthResult is judged: that is exactly how issue #268 happened. A report printed "4/4 healthy (100%)" on one line and "✗ nginx: running" on the next because the printers compared against only "healthy" while the aggregate also accepted "running" — four copies of the same decision that quietly drifted apart.

type RestartContainer

type RestartContainer struct {
	ID      string
	Name    string
	Service string
}

RestartContainer is a minimal container descriptor returned by ContainerList.

type RestartContainerInfo

type RestartContainerInfo struct {
	ID     string
	Health string // healthy, unhealthy, starting, none
}

RestartContainerInfo holds the health state of an inspected container.

type RestartPolicy

type RestartPolicy struct {
	MaxAttempts  int           // default: 3
	PollInterval time.Duration // default: 30s
	RestartDelay time.Duration // default: 5s
}

RestartPolicy configures the behaviour of a Restarter.

func DefaultRestartPolicy

func DefaultRestartPolicy() RestartPolicy

DefaultRestartPolicy returns a RestartPolicy with sensible defaults, overridden by the NSELF_HEALTH_POLL_INTERVAL and NSELF_HEALTH_MAX_RESTARTS env vars if set.

type Restarter

type Restarter struct {
	// contains filtered or unexported fields
}

Restarter polls container health and automatically restarts unhealthy services according to the configured RestartPolicy.

func NewRestarter

func NewRestarter(docker DockerClient, policy RestartPolicy) *Restarter

NewRestarter creates a new Restarter. Call Start to begin polling.

func (*Restarter) Start

func (r *Restarter) Start(ctx context.Context) error

Start begins the health-poll loop in a goroutine. It returns immediately. Cancel ctx to stop the loop cleanly.

func (*Restarter) Status

func (r *Restarter) Status() []ServiceState

Status returns a snapshot of all tracked service states.

type ServiceState

type ServiceState struct {
	Service       string
	Attempts      int
	LastRestart   time.Time
	PermanentFail bool
}

ServiceState records the restart history for a single service.

type ShellDockerClient

type ShellDockerClient struct {
	// contains filtered or unexported fields
}

ShellDockerClient implements DockerClient by delegating to the local docker CLI and the docker.InspectContainer helper.

func NewShellDockerClient

func NewShellDockerClient(projectName string) *ShellDockerClient

NewShellDockerClient returns a ShellDockerClient scoped to the given project. The project name is used to filter containers by the compose project label.

func (*ShellDockerClient) ContainerInspect

func (s *ShellDockerClient) ContainerInspect(ctx context.Context, id string) (RestartContainerInfo, error)

ContainerInspect returns health info for the given container ID using docker.InspectContainer.

func (*ShellDockerClient) ContainerList

func (s *ShellDockerClient) ContainerList(ctx context.Context, _ map[string]string) ([]RestartContainer, error)

ContainerList returns running containers for this project using docker ps.

func (*ShellDockerClient) ContainerRestart

func (s *ShellDockerClient) ContainerRestart(ctx context.Context, id string, timeout int) error

ContainerRestart restarts the given container using docker restart.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL