poll

package
v0.2026266.1306 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Index

Constants

View Source
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

View Source
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")
)
View Source
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).

const (
	PollLocal PollClass = iota
	PollRemote
	PollHeavy
)

type PollCondition

type PollCondition func(ctx context.Context) (ready bool, progress float64, err error)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL