Skip to main content

Module retry

Module retry 

Source
Expand description

Explicit retry policy + full-jitter backoff (agent re-invoke; opt-in in-process). Explicit retry policy for ssh-cli (Rules Rust — retry / backoff).

§Workload and policy scope

ConcernDecision
Product identityOne-shot agent-first SSH CLI (no long-lived client pool)
Who retriesThe agent re-invokes the process; the binary does not
auto-retry exec / scp / sudo-exec / su-exec (side effects)
Classificationcrate::errors::SshCliError::is_retryable + JSON envelope fields
Dependency classSSH TCP + russh only — no HTTP/gRPC product client
In-process loopsOpt-in only via crate::retry::RetryConfig::enabled (default false)

§Why in-process product retry is off by default

Remote shell commands and file transfers are not assumed idempotent. Blind retry would violate least privilege and the one-shot contract (rule: disable retry for operations not marked idempotent). Agents use exit 74 + retryable: true and apply this policy externally.

§Agent contract (documented SLA)

§Delay formula

cap(n)  = min(base_ms * 2^min(n, 16), max_delay_ms)
delay   = uniform(0..=cap)   // full jitter

Monotonic clock for entropy mix: std::time::Instant (not SystemTime). Async waiters must use tokio::time::sleep, never std::thread::sleep.

§Out of scope (identity N/A)

HTTP Retry-After, circuit breaker, retry budget token-bucket, hedged requests, gRPC, OAuth refresh, outbox/saga, Idempotency-Key headers.

Structs§

RetryConfig
Named retry policy (one dependency class: SSH connect / agent re-invoke).

Functions§

backoff_full_jitter
Full jitter: uniform(0..=min(base*2^attempt, max_delay)).
exit_code_is_retryable
Sysexits mapping: which process exits agents may re-invoke with backoff.
wait_for_retry
Prefer operator-hinted wait when present; otherwise full-jitter formula.