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
- Variables
- func DeriveFailURL(pingURL, failURL string) string
- func HostOf(raw string) string
- func NewClient(allowPrivate bool, timeout time.Duration) *http.Client
- func Scrub(err error) error
- func ValidateURL(raw string, allowPrivate bool) (*url.URL, error)
- type Config
- type Health
- type JobPingConfig
- type JobPinger
- func (p *JobPinger) Clear(ctx context.Context, taskID string) error
- func (p *JobPinger) Host(ctx context.Context, taskID string) (string, bool)
- func (p *JobPinger) Notify(taskID, runID, status string)
- func (p *JobPinger) Run(ctx context.Context)
- func (p *JobPinger) Set(ctx context.Context, taskID, pingURL, failURL string) error
- func (p *JobPinger) SetTuning(f func(context.Context) JobTuning)
- func (p *JobPinger) Start(ctx context.Context)
- type JobTuning
- type Options
- type Secrets
- type Service
- type StateStore
- type Status
- type Update
Constants ¶
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.
const ( EnvJobMaxAttempts = "APP_HEARTBEAT_JOB_MAX_ATTEMPTS" EnvJobBackoffBase = "APP_HEARTBEAT_JOB_BACKOFF_BASE" EnvJobBackoffMax = "APP_HEARTBEAT_JOB_BACKOFF_MAX" EnvJobQueue = "APP_HEARTBEAT_JOB_QUEUE" )
Environment variables for per-job ping-out retries.
const ( ResultOK = "ok" ResultFailSent = "fail_reported" ResultUnhealthy = "unhealthy" ResultSendFailed = "error" )
Result words recorded after each tick.
const ( SourceEnv = "env" SourceDashboard = "dashboard" )
Source says where the active ping URL comes from.
Variables ¶
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 DeriveFailURL ¶
DeriveFailURL returns the explicit fail URL, else the ping URL with /fail appended to its path and the query kept.
func HostOf ¶
HostOf returns only the host of raw, the one part of a heartbeat URL safe to show or log.
func NewClient ¶
NewClient is the guarded HTTP client for off-host pings: no proxy, no private destinations unless allowed, same-host redirects only.
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.
type Health ¶
Health reports whether the control plane is fit to claim it is alive, with a short reason word when not.
type JobPingConfig ¶
type JobPingConfig struct {
Timeout time.Duration
AllowPrivate bool
MaxAttempts int
BackoffBase time.Duration
BackoffMax time.Duration
Queue int
}
JobPingConfig is the env-derived configuration of the per-job sender.
func JobPingConfigFromEnv ¶
func JobPingConfigFromEnv(lookup func(string) (string, bool)) (JobPingConfig, error)
JobPingConfigFromEnv reads the shared heartbeat timeout and private switch plus the job retry knobs.
type JobPinger ¶
type JobPinger struct {
// contains filtered or unexported fields
}
JobPinger sends a per-job ping after a scheduled run settles. It never affects the run result.
func NewJobPinger ¶
func NewJobPinger(cfg JobPingConfig, secrets Secrets, logger *slog.Logger) *JobPinger
NewJobPinger builds a sender; secrets must be non-nil.
func (*JobPinger) Host ¶
Host returns the ping URL host, the only part safe to show, and whether one is set.
func (*JobPinger) Notify ¶
Notify queues a ping for a settled run; a full queue drops it so the job is never delayed.
func (*JobPinger) Set ¶
Set stores the ping URL, and the fail URL when given, encrypted. An empty pingURL clears both.
type JobTuning ¶
type JobTuning struct {
MaxAttempts int
BackoffBase time.Duration
BackoffMax time.Duration
Queue int
}
JobTuning is the live retry and queue limits; zero fields fall back to the boot config.
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 (*Service) AgentSilenceURL ¶
AgentSilenceURL returns the stored agent silence URL, or "" when none is set.
func (*Service) Apply ¶
Apply validates and stores an Update, then pings at once so the monitor sees the new URL.
func (*Service) Run ¶
Run pings every interval until ctx ends. It re-reads the target each tick so dashboard edits apply without a restart.
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.