heartbeat

package
v0.8.7 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package heartbeat sends an outbound dead-man ping so an external monitor alerts when the control plane stops, which no in-box alert can do.

Index

Constants

View Source
const (
	EnvURL          = "APP_HEARTBEAT_URL"
	EnvFailURL      = "APP_HEARTBEAT_FAIL_URL"
	EnvInterval     = "APP_HEARTBEAT_INTERVAL"
	EnvTimeout      = "APP_HEARTBEAT_TIMEOUT"
	EnvBody         = "APP_HEARTBEAT_BODY"
	EnvMethod       = "APP_HEARTBEAT_METHOD"
	EnvAllowPrivate = "APP_HEARTBEAT_ALLOW_PRIVATE"
	EnvReconcileMul = "APP_HEARTBEAT_RECONCILE_WINDOWS"
)

Environment variables that configure and lock the heartbeat settings.

View Source
const (
	ResultOK         = "ok"
	ResultFailSent   = "fail_reported"
	ResultUnhealthy  = "unhealthy"
	ResultSendFailed = "error"
)

Result words recorded after each tick.

View Source
const (
	SourceEnv       = "env"
	SourceDashboard = "dashboard"
)

Source says where the active ping URL comes from.

Variables

View Source
var (
	// ErrNoSecrets means no master key is configured, so a URL cannot be stored.
	ErrNoSecrets = errors.New("heartbeat: no secrets store configured")
	// ErrEnvManaged means APP_HEARTBEAT_URL is set and owns the configuration.
	ErrEnvManaged = errors.New("heartbeat: configured by " + EnvURL)
)

Functions

func HostOf

func HostOf(raw string) string

HostOf returns only the host of raw, the one part of a heartbeat URL safe to show or log.

func NewClient

func NewClient(allowPrivate bool, timeout time.Duration) *http.Client

NewClient is the guarded HTTP client for off-host pings: no proxy, no private destinations unless allowed, same-host redirects only.

func Scrub

func Scrub(err error) error

Scrub drops the URL net/http wraps into its errors because it holds the monitor's secret key.

func ValidateURL

func ValidateURL(raw string, allowPrivate bool) (*url.URL, error)

ValidateURL accepts an absolute http or https URL. Errors never echo the URL because it holds a secret key.

Types

type Config

type Config struct {
	URL          string
	FailURL      string
	Interval     time.Duration
	Timeout      time.Duration
	Method       string
	BodyOff      bool
	AllowPrivate bool
	// ReconcileWindows is how many reconcile intervals may pass without a pass before the loop counts as stalled.
	ReconcileWindows int
}

Config is the env-derived heartbeat configuration.

func ConfigFromEnv

func ConfigFromEnv(lookup func(string) (string, bool)) (Config, error)

ConfigFromEnv reads and validates the heartbeat env; an invalid URL is a boot error.

type Health

type Health func(ctx context.Context) (ok bool, reason string)

Health reports whether the control plane is fit to claim it is alive, with a short reason word when not.

type Options

type Options struct {
	Config    Config
	Secrets   Secrets
	State     StateStore
	Health    Health
	Logger    *slog.Logger
	Version   string
	UserAgent string
}

Options carries the service's collaborators.

type Secrets

type Secrets interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	DeleteValue(ctx context.Context, serviceName, envKey string) error
}

Secrets is the slice of the secrets manager the heartbeat needs.

type Service

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

Service pings the configured URL while the control plane is healthy.

func New

func New(o Options) *Service

New builds a Service. Secrets may be nil, which limits configuration to the env.

func (*Service) AgentSilenceURL

func (s *Service) AgentSilenceURL(ctx context.Context) string

AgentSilenceURL returns the stored agent silence URL, or "" when none is set.

func (*Service) Apply

func (s *Service) Apply(ctx context.Context, u Update) error

Apply validates and stores an Update, then pings at once so the monitor sees the new URL.

func (*Service) Run

func (s *Service) Run(ctx context.Context)

Run pings every interval until ctx ends. It re-reads the target each tick so dashboard edits apply without a restart.

func (*Service) Status

func (s *Service) Status(ctx context.Context) (Status, error)

Status reports the current configuration and last outcome.

func (*Service) Tick

func (s *Service) Tick(ctx context.Context)

Tick runs one health check and, when a target exists, one ping.

type StateStore

type StateStore interface {
	GetHeartbeatState(ctx context.Context) (store.HeartbeatState, error)
	SaveHeartbeatState(ctx context.Context, s store.HeartbeatState) error
}

StateStore persists the last ping outcome and the body toggle.

type Status

type Status struct {
	Configured   bool      `json:"configured"`
	Source       string    `json:"source,omitempty"`
	Host         string    `json:"host,omitempty"`
	FailHost     string    `json:"fail_host,omitempty"`
	IntervalSecs int       `json:"interval_seconds"`
	BodyEnabled  bool      `json:"body_enabled"`
	CanStoreURL  bool      `json:"can_store_url"`
	LastPingAt   time.Time `json:"last_ping_at,omitzero"`
	LastResult   string    `json:"last_result,omitempty"`
	LastError    string    `json:"last_error,omitempty"`
	// AgentSilenceHost is the host agents ping when the control plane goes quiet; empty when unset.
	AgentSilenceHost string `json:"agent_silence_host,omitempty"`
}

Status is the API view of the heartbeat; it never carries a URL, only hosts.

type Update

type Update struct {
	URL     *string
	FailURL *string
	Body    *bool
	// AgentSilenceURL is the off-host URL every agent pings when it loses the control plane.
	AgentSilenceURL *string
}

Update is a partial change: nil fields stay as they are, an empty URL string clears that URL.

Jump to

Keyboard shortcuts

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