Documentation
¶
Index ¶
- Constants
- Variables
- func PollUntil(ctx context.Context, cfg PollConfig, cond PollCondition) error
- type PollClass
- type PollCondition
- type PollConfig
- type ResolvedReadiness
- func (rr ResolvedReadiness) PerAttemptFor(class PollClass) time.Duration
- func (rr ResolvedReadiness) PluginEnv() []string
- func (rr ResolvedReadiness) StopGate(name string) PollConfig
- func (rr ResolvedReadiness) ValidateOrdering() error
- func (rr ResolvedReadiness) Wait(name string, class PollClass) PollConfig
- func (rr ResolvedReadiness) WaitCapped(name string, class PollClass, cap time.Duration) PollConfig
- func (rr ResolvedReadiness) WatchProgress(name string, class PollClass, noProgress time.Duration) PollConfig
Constants ¶
const ( ReadinessIntervalLocalFallback = readinessIntervalLocalFallback ReadinessIntervalRemoteFallback = readinessIntervalRemoteFallback ReadinessIntervalHeavyFallback = readinessIntervalHeavyFallback ReadinessPerAttemptFallback = readinessPerAttemptFallback ReadinessPerAttemptHeavyFallback = readinessPerAttemptHeavyFallback ReadinessNoProgressFallback = readinessNoProgressFallback ReadinessAbsoluteCapFallback = readinessAbsoluteCapFallback ReadinessStopGraceFallback = readinessStopGraceFallback )
Exported fallback aliases — the exported surface vmshared (and, through it, the VM plugin) re-export as the operator-visible fallback defaults. The unexported consts above stay the intra-spec single source; these expose them across the package boundary without a second literal.
Variables ¶
var ( // ErrPollStalled — the high-water mark did not advance within NoProgress. ErrPollStalled = errors.New("poll: no forward progress within the no-progress window") // ErrPollCapExceeded — the absolute wall-clock ceiling elapsed. ErrPollCapExceeded = errors.New("poll: absolute cap exceeded") // ErrPollFatal — wrap a cond error in this to abort the poll immediately. ErrPollFatal = errors.New("poll: fatal condition error") // ErrPollConfig — PollUntil's own entry validation rejected the config. ErrPollConfig = errors.New("poll: invalid configuration") )
var ReadinessProvider = func() ResolvedReadiness { rr, _ := ResolveReadiness(nil) return rr }
ReadinessProvider returns the resolved readiness bounds the executors' waits use. Defaults to the built-in bounds; charly overrides it at init with its project-aware loadedReadiness (charly/readiness_config.go).
Functions ¶
func PollUntil ¶
func PollUntil(ctx context.Context, cfg PollConfig, cond PollCondition) error
PollUntil drives cond to readiness using the modes described on PollConfig. Returns nil on ready; a %w-wrapped ErrPollStalled / ErrPollCapExceeded / ErrPollFatal / ErrPollConfig, or ctx.Err(), otherwise. Context-cancellable; deterministic under an injected clock (zero real sleeping in tests).
Types ¶
type PollClass ¶
type PollClass int
PollClass selects the tick-interval band only (never the deadline). Local = in-process/loopback probes (podman exec, libvirt domain-state, supervisord); Remote = one-ssh/network-round-trip probes; Heavy = full-suite subprocess probes (each tick runs a whole `charly check live` pass).
type PollCondition ¶
PollCondition is the caller's readiness probe, invoked once per tick under a per-attempt timeout context.
ready — the awaited state is reached; PollUntil returns nil.
progress — a MONOTONIC forward-motion score (higher == more progress, e.g. a
count or an AI score). The no-progress watchdog resets only when
this reaches a NEW HIGH-WATER value, so oscillation/regression
cannot masquerade as progress. Ignored in cap-only mode
(NoProgress<=0) — pass 0 for binary/edge sites.
err — wrap ErrPollFatal to abort IMMEDIATELY (unrecoverable: process
died, auth/permission error). Any other non-nil err is transient
(target not up yet): routed to OnTransient, treated as not-ready,
and does NOT advance the high-water mark.
type PollConfig ¶
type PollConfig struct {
Name string // label woven into log lines + errors, e.g. "ssh-ready check-k3s-vm"
Interval time.Duration // tick cadence (pacing only; never the deadline). >0 required.
PerAttempt time.Duration // per-cond context timeout (the never-hang kill-switch for a blocking probe). >0 required.
NoProgress time.Duration // monotonic stall window; 0 disables (cap-only mode).
AbsoluteCap time.Duration // generous never-hang ceiling; 0 means "no cap" (NoProgress must then be >0).
// OnTick (optional) is host-side observability per tick. NEVER AI-visible
// (matches check_watchdog.go doctrine). sinceAdvance is time since the last
// high-water advance (0 in cap-only mode).
OnTick func(elapsed time.Duration, progress float64, sinceAdvance time.Duration)
// OnTransient (optional) receives each transient (non-fatal) cond error.
OnTransient func(err error)
// contains filtered or unexported fields
}
PollConfig parameterizes one PollUntil call. Build it via ResolvedReadiness's Wait / WaitCapped / StopGate so no call site carries a magic literal.
type ResolvedReadiness ¶
type ResolvedReadiness struct {
IntervalLocal time.Duration
IntervalRemote time.Duration
IntervalHeavy time.Duration
PerAttempt time.Duration
PerAttemptHeavy time.Duration
NoProgress time.Duration
AbsoluteCap time.Duration
StopGrace time.Duration
}
ResolvedReadiness is the load-time-materialized, validated bounds set (resolveReadiness in build.go merges flag/env → defaults.readiness → the named fallback constants, then ReadinessConfig.Validate enforces ordering). The zero value is SAFE — every builder falls back to the compiled-in fallback constants — so a site that has not yet been threaded the resolved set still gets sane, never-hang bounds (it just isn't operator-tunable until threaded).
func ResolveReadiness ¶
func ResolveReadiness(rc *spec.ReadinessConfig) (ResolvedReadiness, error)
ResolveReadiness materializes the validated ResolvedReadiness from a `defaults.readiness:` block plus CHARLY_READINESS_* env overrides plus the named fallbacks. Nil-safe (nil → all fallbacks/env). The SINGLE resolver — charly core (loadedReadiness, from the project config) AND the out-of-process plugins (nil + the host-threaded env) both call it.
func (ResolvedReadiness) PerAttemptFor ¶
func (rr ResolvedReadiness) PerAttemptFor(class PollClass) time.Duration
PerAttemptFor returns the effective per-attempt never-hang bound for a poll class (the field value, or the built-in fallback when unset). The unexported perAttempt/perAttemptHeavy accessors collide on export with the PerAttempt/PerAttemptHeavy struct fields, so consumers reach the bound through this class-keyed facade.
func (ResolvedReadiness) PluginEnv ¶
func (rr ResolvedReadiness) PluginEnv() []string
PluginEnv emits the CHARLY_READINESS_* entries (KEY=VALUE) for this RESOLVED readiness, so an out-of-process plugin — which cannot LoadUnified — re-reads the host-resolved bounds via its own ResolveReadiness. The host appends these to a plugin's spawn env (charly's LocalTransport.Connect). Durations round-trip through String() ⟷ resolveReadinessDuration.
func (ResolvedReadiness) StopGate ¶
func (rr ResolvedReadiness) StopGate(name string) PollConfig
StopGate builds a settle/teardown PollConfig: cap-only at StopGrace (a clean timeout for the binary "is it down yet?" — the caller performs the force fallback on ErrPollCapExceeded). Replaces the 60s/180s/10s stop magic numbers with one config-sourced grace; no 2× multiplier.
func (ResolvedReadiness) ValidateOrdering ¶
func (rr ResolvedReadiness) ValidateOrdering() error
ValidateOrdering enforces the bound ordering on the RESOLVED set (must run post-env, not on the raw YAML — an env override must not slip a bad bound through): each interval <= no_progress; no_progress <= absolute_cap; poll_interval_local <= stop_grace <= absolute_cap.
func (ResolvedReadiness) Wait ¶
func (rr ResolvedReadiness) Wait(name string, class PollClass) PollConfig
Wait builds a MONOTONIC readiness PollConfig: the no-progress watchdog is active (the load-robust early-out), with a generous absolute cap as the never-hang backstop. Use ONLY where cond reports a genuinely advancing high-water progress score (supervisord settled-count, check-live pass tally, AI score). For binary/edge markers use WaitCapped instead.
func (ResolvedReadiness) WaitCapped ¶
func (rr ResolvedReadiness) WaitCapped(name string, class PollClass, cap time.Duration) PollConfig
WaitCapped builds a CAP-ONLY PollConfig (NoProgress disabled): wait until cond is ready or the generous cap elapses. Use for BINARY/EDGE readiness (ssh-up, boot_id, cloud-init-done, file-present, channel-up) where the marker is frozen until the end, AND for AUTHOR/CALLER-declared deadlines (eventually:, WaitSeconds, guest-exec maxWait) which must be preserved exactly. cap<=0 falls back to the generous config absolute_cap.
func (ResolvedReadiness) WatchProgress ¶
func (rr ResolvedReadiness) WatchProgress(name string, class PollClass, noProgress time.Duration) PollConfig
WatchProgress builds a NO-CAP monotonic watchdog (NoProgress active, no absolute cap) for an intentionally unbounded long-runner: the AI iteration loop, whose run must NOT be killed at a wall-clock cap as long as the score keeps improving. noProgress<=0 falls back to the config no_progress.