Documentation
¶
Overview ¶
Package canary decides when a staged canary release advances, promotes or rolls back, and runs the level-triggered reconciler that applies it.
Index ¶
Constants ¶
const ( // MaxWeight is the largest share ingress gives a canary. MaxWeight = canarypolicy.MaxWeight // Full is the stage value that means promote. Full = canarypolicy.Full )
const ( EnvStages = canarypolicy.EnvStages EnvInterval = canarypolicy.EnvInterval EnvMaxErrorRate = canarypolicy.EnvMaxErrorRate EnvMaxP95Ratio = canarypolicy.EnvMaxP95Ratio EnvMinRequests = canarypolicy.EnvMinRequests EnvP95FloorMS = canarypolicy.EnvP95FloorMS EnvTick = canarypolicy.EnvTick )
The APP_CANARY_* variable names.
Variables ¶
var ( // DefaultPolicy returns the env-tuned default policy. DefaultPolicy = canarypolicy.DefaultPolicy // DefaultLimits returns the env-tuned global limits. DefaultLimits = canarypolicy.DefaultLimits // ParseStages parses a comma separated stage list. ParseStages = canarypolicy.ParseStages // ValidateStages checks a stage schedule. ValidateStages = canarypolicy.ValidateStages // OSEnv reads the process environment. OSEnv = canarypolicy.OSEnv )
Functions ¶
Types ¶
type Actions ¶
type Actions interface {
Promote(ctx context.Context, rel store.CanaryRelease) error
Rollback(ctx context.Context, rel store.CanaryRelease, reason string) error
}
Actions are the side effects a decision can trigger. Both must be idempotent: a tick that fails half way is simply repeated.
type Dials ¶
type Dials struct {
// contains filtered or unexported fields
}
Dials is the shared record of which upstream is which release.
func DefaultDials ¶
func DefaultDials() *Dials
DefaultDials is the process-wide record the ingress controller writes and the reconciler reads, mirroring ingress.DefaultRequestStats.
type Input ¶
type Input struct {
Policy Policy
Limits Limits
// Stage is the index into Policy.Stages currently serving.
Stage int
// Elapsed is how long this stage has been observed.
Elapsed time.Duration
Canary Sample
Baseline Sample
}
Input is everything Decide needs; it holds no clock or I/O.
type Pair ¶
Pair is the ingress upstream addresses (host:port) of an app's stable release and its canary, as the ingress controller last routed them.
type Policy ¶
type Policy = canarypolicy.Policy
Policy is the stage schedule and thresholds of one canary.
type Progress ¶
type Progress struct {
Stage int `json:"stage"`
StageCount int `json:"stage_count"`
ElapsedSecs int `json:"elapsed_secs"`
IntervalSecs int `json:"interval_secs"`
CanaryRequests uint64 `json:"canary_requests"`
CanaryErrRate float64 `json:"canary_error_rate"`
CanaryP95MS float64 `json:"canary_p95_ms"`
StableRequests uint64 `json:"stable_requests"`
StableErrRate float64 `json:"stable_error_rate"`
StableP95MS float64 `json:"stable_p95_ms"`
Next string `json:"next"`
Breaching bool `json:"breaching"`
}
Progress is the live view of a staged canary for the dashboard, CLI and MCP.
type Reconciler ¶
type Reconciler struct {
// contains filtered or unexported fields
}
Reconciler converges staged canaries toward their desired stage. Desired state is the release row; the per-stage observation window is the only in-memory state and a restart just reopens it.
func NewReconciler ¶
func NewReconciler(s Store, stats Stats, dials *Dials, actions Actions, limits Limits, now func() time.Time, logger *slog.Logger) *Reconciler
NewReconciler builds a reconciler. now may be nil for the wall clock.
func (*Reconciler) Progress ¶
func (r *Reconciler) Progress(rel store.CanaryRelease) (Progress, bool)
Progress returns the current observation of rel, false when it is not being observed (not staged, paused, or not yet receiving traffic).
func (*Reconciler) Reconcile ¶
func (r *Reconciler) Reconcile(ctx context.Context) error
Reconcile evaluates every staged canary once.
func (*Reconciler) Run ¶
func (r *Reconciler) Run(ctx context.Context)
Run reconciles every tick until ctx is done.
type Sample ¶
type Sample struct {
Requests uint64
Errors uint64
Latency [telemetry.LatencyBucketCount]uint64
}
Sample is one release's traffic over a window.
func SampleFrom ¶
func SampleFrom(u telemetry.UpstreamStat) Sample
SampleFrom converts an ingress upstream counter.
type Stats ¶
type Stats interface {
UpstreamTotals() map[string]telemetry.UpstreamStat
}
Stats reads cumulative per-upstream counters; ingress.RequestStats satisfies it.