Documentation
¶
Overview ¶
Package status provides a small, reusable readiness aggregation layer.
Microservice components implement the Prober interface — a single method Status(ctx) error where nil means healthy and any non-nil error means unhealthy (the error message is surfaced as the probe message).
An Aggregator collects named local probes and downstream StatusReply sources, runs them (with per-probe timeouts), caches the merged StatusReply for a configurable TTL, and single-flights concurrent callers so /health cannot be turned into a DDoS amplifier.
Index ¶
- Constants
- Variables
- type Aggregator
- func (a *Aggregator) Register(name string, p Prober) *Aggregator
- func (a *Aggregator) RegisterDownstream(name string, fetch DownstreamFetcher) *Aggregator
- func (a *Aggregator) RegisterFunc(name string, fn func(ctx context.Context) error) *Aggregator
- func (a *Aggregator) Reply(ctx context.Context) *apiv1_status.StatusReply
- type DownstreamFetcher
- type Option
- type Prober
- type ProberFunc
- type Probes
Constants ¶
const ( // StatusOK marks an individual probe as healthy. StatusOK = "OK" // StatusFail marks an individual probe as unhealthy. StatusFail = "FAIL" // ServiceStatusOK / ServiceStatusFail are the top-level rollup format, // e.g. "STATUS_OK_apigw" / "STATUS_FAIL_apigw". ServiceStatusOK = "STATUS_OK_%s" ServiceStatusFail = "STATUS_FAIL_%s" )
Variables ¶
var ( BuildVariableGitCommit string = "undef" BuildVariableTimestamp string = "undef" BuildVariableGoVersion string = "undef" BuildVariableGoArch string = "undef" BuildVariableGitBranch string = "undef" BuildVersion string = "undef" )
Build-time variables populated via `-ldflags "-X 'github.com/SUNET/vc/pkg/status.<Name>=<value>'"` and exposed in every StatusReply for operator visibility.
var ErrUninitialized = errors.New("component not initialized")
ErrUninitialized is a convenience sentinel for probes that fail because their component was not wired up (e.g. optional gRPC client is nil).
Functions ¶
This section is empty.
Types ¶
type Aggregator ¶
type Aggregator struct {
// contains filtered or unexported fields
}
Aggregator collects local probers and downstream services and produces a merged StatusReply. Safe for concurrent use.
func New ¶
func New(serviceName string, opts ...Option) *Aggregator
New returns an Aggregator for the given service. Sensible defaults: 2 second probe timeout, 10 second cache TTL.
func (*Aggregator) Register ¶
func (a *Aggregator) Register(name string, p Prober) *Aggregator
Register adds a local component to be probed. The probe will appear in the reply as "<serviceName>.<name>".
func (*Aggregator) RegisterDownstream ¶
func (a *Aggregator) RegisterDownstream(name string, fetch DownstreamFetcher) *Aggregator
RegisterDownstream adds a downstream service whose probes are inlined into the aggregated reply. If fetch returns an error, a single failing probe named after the downstream is emitted instead.
func (*Aggregator) RegisterFunc ¶
func (a *Aggregator) RegisterFunc(name string, fn func(ctx context.Context) error) *Aggregator
RegisterFunc is a convenience wrapper around Register for anonymous checks.
func (*Aggregator) Reply ¶
func (a *Aggregator) Reply(ctx context.Context) *apiv1_status.StatusReply
Reply returns the (possibly cached) aggregated StatusReply. Concurrent callers that arrive during a refresh block on the in-flight computation rather than starting their own, so downstream fanout is single-flighted. A nil receiver returns an empty (but well-formed) StatusReply so callers don't need to guard against uninitialized aggregators.
type DownstreamFetcher ¶
type DownstreamFetcher func(ctx context.Context) (*apiv1_status.StatusReply, error)
DownstreamFetcher retrieves a StatusReply from a downstream service (for example via a gRPC Status RPC). The returned reply's probes are inlined verbatim into the aggregate — they should already be service-prefixed (e.g. "issuer.signer") by the callee's own Aggregator.
type Option ¶
type Option func(*Aggregator)
Option configures a new Aggregator.
func WithCacheTTL ¶
WithCacheTTL sets how long a computed StatusReply is served before the next call recomputes it. Zero disables caching (every call recomputes).
func WithProbeTimeout ¶
WithProbeTimeout sets the per-probe timeout applied to every Prober and DownstreamFetcher invocation.
type Prober ¶
Prober reports the readiness of a single component. Return nil when the component is healthy; any non-nil error is treated as unhealthy and its message is surfaced verbatim to the caller.
The method is named HealthProbe (rather than Status) so it does not collide with unrelated Status methods on the same type (e.g. token status list operations, gRPC Status RPCs).
type ProberFunc ¶
ProberFunc adapts a plain function to the Prober interface.
func (ProberFunc) HealthProbe ¶
func (f ProberFunc) HealthProbe(ctx context.Context) error
HealthProbe implements Prober.
type Probes ¶
type Probes []*apiv1_status.StatusProbe
Probes is a mutable slice of proto StatusProbe pointers. See Check for the mutation contract.
func (Probes) Check ¶
func (probes Probes) Check(serviceName string) *apiv1_status.StatusReply
Check builds a StatusReply from the collected probes. Each probe carries its own status ("OK" / "FAIL"), and Data.Status carries a service-level rollup ("STATUS_OK_<svc>" / "STATUS_FAIL_<svc>") — FAIL when any probe is unhealthy. Locally-produced probes are prefixed with "<svc>." (so operators see "apigw.db" etc.); probes forwarded from a downstream service already carry their own "<svc>." prefix and are left untouched.
Each input probe is shallow-copied before being adjusted so callers can safely pass probes that originated from shared/cached protobuf messages (e.g. downstream StatusReply objects) without side effects.