Documentation
¶
Overview ¶
Package sender turns buffered reports and pending events into ingest requests and drives the retry matrix. One batch is held across all its retries so its idempotency_key stays stable (server-side report dedupe), while sent_at is refreshed on every attempt so a retried batch is not read as clock skew. On a 202 the batch's reports and events are removed from the buffer and queue (remove-on-202, at-least-once). The four outcomes map straight from the status code: 202 succeeds, 429/404/5xx back off, the terminal 4xx (400/413/422) discards the poison batch, and 401/403/409 quarantine without wiping.
Index ¶
Constants ¶
const ( DefaultBaseBackoff = 2 * time.Second DefaultCapBackoff = 10 * time.Minute // DefaultQuarantineFloor is the minimum wait after a persistent 401. The // agent never hammers and never wipes: it backs off long and keeps its data, // so a re-enroll or an external token rotation can recover it. DefaultQuarantineFloor = 5 * time.Minute )
Backoff parameters: full-jitter exponential backoff from a 2s base to a 10min cap for retryable outcomes.
Variables ¶
This section is empty.
Functions ¶
func MetaDigest ¶ added in v0.5.0
MetaDigest fingerprints a host profile for change detection: sorted key=value pairs hashed, volatile keys dropped, ram_total_bytes compared in whole GiB.
The GiB rounding is not cosmetic. MemTotal is derived from totalram_pages, and a balloon driver (virtio_balloon on KVM/Proxmox, hv_balloon on Hyper-V) hands pages back and forth at runtime, so a ballooned guest reports a MemTotal that drifts by tens of MiB all day long. Nobody resizes a VM by less than a gigabyte, so whole GiB keeps every real change and drops the entire balloon noise floor.
Exported so the wiring that feeds SetMeta can be tested against the same key the sender compares on.
Types ¶
type Options ¶
type Options struct {
Client *http.Client
URL string
TokenFn func() string
InstanceID string
AgentVersion string
Clock platform.Clock
Buffer *buffer.Ring
Events *event.Queue
Config func() *config.Config
Emitter event.Emitter
NewID func() string // fresh UUIDv4 for idempotency keys
Log *slog.Logger
// Fingerprint is attached to batches until the first 202 (and re-attached
// when it changes). May be nil.
Fingerprint map[string]string
// Meta is the INITIAL host profile (hostinfo.Meta). It decorates the first report
// of every batch until a batch that carried it gets a 202 - delivery-confirmed,
// unlike the old assemble-time flag, which lost the profile for the whole
// process lifetime when the bootstrap report was evicted from the ring
// during a long initial ingest outage. May be nil.
//
// After construction the profile is owned by the Sender: hand a re-read profile
// to SetMeta, which re-arms delivery only when it actually differs.
Meta map[string]string
// OnConfigVersion is called when a 202 advertises a newer config version.
OnConfigVersion func(v uint32)
// Tuning (zero uses defaults).
BaseBackoff time.Duration
CapBackoff time.Duration
QuarantineFloor time.Duration
Jitter jitterFn
}
Options configures a Sender. Buffer, Events, Config, Clock, URL, TokenFn and InstanceID are required; the rest have defaults.
type Sender ¶
type Sender struct {
// contains filtered or unexported fields
}
Sender drives delivery.
func (*Sender) Run ¶
Run drives delivery until ctx is done. It holds a batch across retries so the idempotency key is stable, and only releases it on a terminal outcome (202 or a discard). On ctx cancellation any in-flight reports and events stay in the buffer and queue for the exit spool.
func (*Sender) SetMeta ¶ added in v0.5.0
SetMeta installs a freshly collected host profile.
The wire contract sends meta "only on change plus the first report after start" (SERVER-AGENT.md 4.1), so this is the "on change" half. An unchanged profile is a complete no-op: neither the stored map nor the delivery flag move, and the next batch stays profile-free. A changed profile re-arms the attach flag, so the next batch carries it and mark-after-202 confirms it exactly like the bootstrap profile.
A restart needs no special case: a fresh Sender starts with metaSent false, so the first report of every process life carries the profile whether it changed or not.