mirror of
https://github.com/luxfi/vm.git
synced 2026-10-30 15:13:40 +00:00
137 lines
3.9 KiB
Go
137 lines
3.9 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package health
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/luxfi/log"
|
|
"github.com/luxfi/metric"
|
|
)
|
|
|
|
const (
|
|
// CheckLabel is the label used to differentiate between health checks.
|
|
CheckLabel = "check"
|
|
// TagLabel is the label used to differentiate between health check tags.
|
|
TagLabel = "tag"
|
|
// AllTag is automatically added to every registered check.
|
|
AllTag = "all"
|
|
// ApplicationTag checks will act as if they specified every tag that has
|
|
// been registered.
|
|
// Registering a health check with this tag will ensure that it is always
|
|
// included in all health query results.
|
|
ApplicationTag = "application"
|
|
)
|
|
|
|
var _ Health = (*health)(nil)
|
|
|
|
// Health defines the full health service interface for registering, reporting
|
|
// and refreshing health checks.
|
|
type Health interface {
|
|
Registerer
|
|
Reporter
|
|
|
|
// Start running periodic health checks at the specified frequency.
|
|
// Repeated calls to Start will be no-ops.
|
|
Start(ctx context.Context, freq time.Duration)
|
|
|
|
// Stop running periodic health checks. Stop should only be called after
|
|
// Start. Once Stop returns, no more health checks will be executed.
|
|
Stop()
|
|
}
|
|
|
|
// Registerer defines how to register new components to check the health of.
|
|
type Registerer interface {
|
|
RegisterReadinessCheck(name string, checker Checker, tags ...string) error
|
|
RegisterHealthCheck(name string, checker Checker, tags ...string) error
|
|
RegisterLivenessCheck(name string, checker Checker, tags ...string) error
|
|
}
|
|
|
|
// Reporter returns the current health status.
|
|
type Reporter interface {
|
|
Readiness(tags ...string) (map[string]Result, bool)
|
|
Health(tags ...string) (map[string]Result, bool)
|
|
Liveness(tags ...string) (map[string]Result, bool)
|
|
}
|
|
|
|
type health struct {
|
|
log log.Logger
|
|
readiness *worker
|
|
health *worker
|
|
liveness *worker
|
|
}
|
|
|
|
func New(log log.Logger, registerer metric.Registerer) (Health, error) {
|
|
metricsInstance := metric.NewWithRegistry("health", registerer.(metric.Registry))
|
|
failingChecks := metricsInstance.NewGaugeVec(
|
|
"checks_failing",
|
|
"number of currently failing health checks",
|
|
[]string{CheckLabel, TagLabel},
|
|
)
|
|
return &health{
|
|
log: log,
|
|
readiness: newWorker(log, "readiness", failingChecks),
|
|
health: newWorker(log, "health", failingChecks),
|
|
liveness: newWorker(log, "liveness", failingChecks),
|
|
}, nil
|
|
}
|
|
|
|
func (h *health) RegisterReadinessCheck(name string, checker Checker, tags ...string) error {
|
|
return h.readiness.RegisterMonotonicCheck(name, checker, tags...)
|
|
}
|
|
|
|
func (h *health) RegisterHealthCheck(name string, checker Checker, tags ...string) error {
|
|
return h.health.RegisterCheck(name, checker, tags...)
|
|
}
|
|
|
|
func (h *health) RegisterLivenessCheck(name string, checker Checker, tags ...string) error {
|
|
return h.liveness.RegisterCheck(name, checker, tags...)
|
|
}
|
|
|
|
func (h *health) Readiness(tags ...string) (map[string]Result, bool) {
|
|
results, healthy := h.readiness.Results(tags...)
|
|
if !healthy {
|
|
h.log.Warn("failing check",
|
|
log.UserString("namespace", "readiness"),
|
|
log.Reflect("reason", results),
|
|
)
|
|
}
|
|
return results, healthy
|
|
}
|
|
|
|
func (h *health) Health(tags ...string) (map[string]Result, bool) {
|
|
results, healthy := h.health.Results(tags...)
|
|
if !healthy {
|
|
h.log.Warn("failing check",
|
|
log.UserString("namespace", "health"),
|
|
log.Reflect("reason", results),
|
|
)
|
|
}
|
|
return results, healthy
|
|
}
|
|
|
|
func (h *health) Liveness(tags ...string) (map[string]Result, bool) {
|
|
results, healthy := h.liveness.Results(tags...)
|
|
if !healthy {
|
|
h.log.Warn("failing check",
|
|
log.UserString("namespace", "liveness"),
|
|
log.Reflect("reason", results),
|
|
)
|
|
}
|
|
return results, healthy
|
|
}
|
|
|
|
func (h *health) Start(ctx context.Context, freq time.Duration) {
|
|
h.readiness.Start(ctx, freq)
|
|
h.health.Start(ctx, freq)
|
|
h.liveness.Start(ctx, freq)
|
|
}
|
|
|
|
func (h *health) Stop() {
|
|
h.readiness.Stop()
|
|
h.health.Stop()
|
|
h.liveness.Stop()
|
|
}
|