Documentation
¶
Overview ¶
Package observe keeps durable, revision-fenced observations of expensive or external checks so pages and APIs serve the last saved result at once while refreshes run as bounded background jobs.
Each registered Spec describes one capability kind: how to enumerate its keys, the configuration revision a key currently has, whether the capability is enabled, and the check to run. A refresh is admitted at most once per in-flight generation (one hundred concurrent requests make one job), runs with a timeout and a bounded number of attempts, and only writes its result when the configuration revision it was queued for is still current. The last successful result stays visible with its age when a newer attempt fails; it is never relabelled as the newer attempt.
Index ¶
- Constants
- Variables
- func Age(seconds int64) string
- func Migrations() fs.FS
- type Attempt
- type Observation
- type Ref
- type Result
- type Saved
- type Service
- func (s *Service) All(ctx context.Context) ([]Observation, error)
- func (s *Service) Forget(ctx context.Context, kind, key string) error
- func (s *Service) Get(ctx context.Context, kind, key string) (Observation, error)
- func (s *Service) Kinds() []string
- func (s *Service) List(ctx context.Context, kind string) ([]Observation, error)
- func (s *Service) Record(ctx context.Context, kind, key, revision string, res Result, runErr error, ...) error
- func (s *Service) Refresh(ctx context.Context, kind, key string) (Ref, error)
- func (s *Service) Register(spec Spec)
- func (s *Service) Tick(ctx context.Context) error
- type Spec
Constants ¶
const JobKindPrefix = "observe."
JobKindPrefix prefixes the job kind of every capability ("observe.<kind>"), so a disabled capability's queued refreshes wait unclaimed (and can be parked) instead of failing as unregistered work.
const ServiceName = "observe"
ServiceName is the kernel service name the admin module publishes.
Variables ¶
var ( ErrUnknownKind = errors.New("observe: unknown capability kind") ErrDisabled = errors.New("observe: capability disabled") ErrNotFound = errors.New("observe: key not found") ErrManual = errors.New("observe: results of this kind are recorded by explicit actions only") )
Errors returned by Refresh.
Functions ¶
Types ¶
type Attempt ¶
type Attempt struct {
Status string `json:"status" enum:"waiting,running,succeeded,failed,superseded"`
StartedAt *string `json:"started_at"`
FinishedAt *string `json:"finished_at"`
Number int `json:"number" doc:"1-based attempt number within the job; 0 while waiting"`
DurationMS *int64 `json:"duration_ms" doc:"Null until the attempt finished"`
Error string `json:"error" doc:"Sanitized failure reason; empty on success"`
Remediation string `json:"remediation"`
JobID string `json:"job_id"`
Generation int64 `json:"generation"`
}
Attempt is the latest refresh attempt, independent from the saved result.
type Observation ¶
type Observation struct {
Kind string `json:"kind"`
Key string `json:"key"`
Status string `` /* 222-byte string literal not displayed */
Attempt *Attempt `json:"attempt" doc:"Null before the first refresh"`
Saved *Saved `json:"saved" doc:"Null until a refresh succeeded"`
Enabled bool `json:"enabled"`
}
Observation is the readable state of one key.
type Ref ¶
type Ref struct {
Kind string `json:"kind"`
Key string `json:"key"`
JobID string `json:"job_id"`
Generation int64 `json:"generation"`
Deduped bool `json:"deduplicated" doc:"True when a refresh for this key was already queued or running"`
}
Ref identifies an admitted or deduplicated refresh.
type Result ¶
Result is what a check returns. Scope names the evidence level, e.g. "connectivity" or "discovery"; it is saved beside the data so readers never mistake reachability for a verified operation.
type Saved ¶
type Saved struct {
At string `json:"at"`
AgeSeconds int64 `json:"age_seconds"`
Revision string `json:"revision"`
RevisionMatch *bool `json:"revision_match" doc:"Null when the key's current revision cannot be read"`
DurationMS *int64 `json:"duration_ms"`
Scope string `json:"scope"`
Data json.RawMessage `json:"data"`
}
Saved is the last successful read, kept even when newer attempts fail.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service owns the observations table and the refresh jobs.
func New ¶
New returns a service on d; q must be the queue whose workers will run the refreshes. Register specs before the queue starts.
func (*Service) All ¶
func (s *Service) All(ctx context.Context) ([]Observation, error)
All returns every saved observation of every registered kind.
func (*Service) Forget ¶
Forget deletes the saved observation of key (for a removed profile). Queued refreshes for it are superseded when they run.
func (*Service) Get ¶
Get returns the observation for key. A key that was never refreshed is returned with status "never" when it exists (Revision != ""), else ErrNotFound.
func (*Service) Record ¶
func (s *Service) Record(ctx context.Context, kind, key, revision string, res Result, runErr error, duration time.Duration) error
Record saves the outcome of a check that ran synchronously (an explicit operator action) as the key's newest attempt, outside the job path. The generation is unchanged; a refresh queued for the same key keeps its own fence. A nil err saves the result as the last success; otherwise the previous success is kept and only the attempt is recorded.
func (*Service) Refresh ¶
Refresh admits one background refresh for key and returns at once with its job reference. A refresh already queued or running for the key is returned instead of a second one (Deduped). It never runs the check in the caller's request.
func (*Service) Register ¶
Register adds a capability kind and its job handler. Panics on an empty kind or a duplicate (a programmer error, like duplicate routes).
func (*Service) Tick ¶
Tick is the scheduler: run it from a queue cron. It parks queued refreshes of kinds no longer registered (a disabled capability), releases parked refreshes of registered kinds once, then admits a refresh for every key whose saved result is missing, stale or for another revision, up to MaxInFlight per kind. Disabled kinds are skipped entirely.
type Spec ¶
type Spec struct {
Kind string
// Timeout bounds one attempt (default 20s). MaxAttempts bounds retries
// through the job queue (default 3). Freshness is how long a success is
// served as fresh and how often the scheduler refreshes keys (default
// 15m; <= 0 means refresh only on demand). MaxInFlight caps queued or
// running refreshes of this kind admitted by the scheduler (default 2).
Timeout time.Duration
MaxAttempts int
Freshness time.Duration
MaxInFlight int
// Keys enumerates the keys the scheduler refreshes (nil: on demand only).
Keys func(ctx context.Context) ([]string, error)
// Revision returns the key's current configuration revision, or "" when
// the key no longer exists. A result is only saved while the revision it
// was queued for is still current.
Revision func(ctx context.Context, key string) (string, error)
// Enabled reports whether the capability may run (nil: always). A
// disabled capability is neither scheduled nor refreshed on demand;
// its saved rows are kept.
Enabled func(ctx context.Context) bool
// Run performs the check for key at revision. Its error message is
// stored (truncated) and shown to operators: never include credentials.
Run func(ctx context.Context, key, revision string) (Result, error)
// Remediation is the operator hint stored with a failed attempt.
Remediation string
// Manual marks a kind whose results come only from Record (an explicit
// operator action with input the job queue cannot carry, such as a
// pasted key). Refresh returns ErrManual, the scheduler never admits
// it, and Run is never called.
Manual bool
}
Spec registers one capability kind.