Documentation
¶
Overview ¶
Package backoff is the retry arithmetic of plan 6.6 and 6.8 item 7 (U-16): an exponential schedule with jitter for the watcher's restart of its `message watch` child (1 s doubling to a 30 s cap, and a fixed 5 min once that pace has failed ten times — card 34) and for adapter errors (1 s doubling to a 5 min cap), and the retryability predicate — only `rate_limited` and `unavailable` (and a crash or signal, which adapterkit.Spawn already maps to `unavailable`) are ever retried; `invalid_input`, `unauthorized`, `loop_detected` and every other code are terminal. Nothing here sleeps or keeps time: a Schedule hands back durations and the caller (P3-5's watcher, the socket poster's retry loop) waits on them, which is what keeps the schedule testable under testing/synctest and its sequence exact for a seeded source.
Index ¶
Constants ¶
const ( // WatchRestartMin and WatchRestartMax bound the restart of the // `message watch` child (6.6: "exponential backoff 1 s..30 s with // jitter"). WatchRestartMin = time.Second WatchRestartMax = 30 * time.Second // WatchSlowRetry is the pace the watcher falls back to once the restarts // above have failed often enough to trip its give-up rule on a failure a // restart can fix (card 34): it tries again at least this often for as // long as the session lives, instead of exiting. With the schedule's // jitter a delay is between half of it and all of it. WatchSlowRetry = 5 * time.Minute // AdapterErrorMin and AdapterErrorMax bound retries of a failed // adapter call (6.8 item 7: "exponential with jitter, capped at 5 min"). AdapterErrorMin = time.Second AdapterErrorMax = 5 * time.Minute )
The schedules the plan names, and the slow retry of card 34.
const Factor = 2
Factor is the growth per attempt.
Variables ¶
This section is empty.
Functions ¶
func Retryable ¶
Retryable reports whether a failed adapter call with this code may be retried (4.3, 4.6, U-16): only rate_limited and unavailable. Every other code — invalid_input, unauthorized, loop_detected, and the rest — is terminal, and so is a code this harness does not recognise (4.6 maps an unknown code to internal). The switch is exhaustive over protocol.Code so a code added to the taxonomy must be classified here on purpose.
func RetryableError ¶
RetryableError is Retryable over an error: a *protocol.Error anywhere in the chain is classified by its code (adapterkit.Spawn maps a timeout, a signal death and a missing executable to unavailable, so those retry), and any other error — including nil — is not retried, because an error the harness cannot classify is a bug, not a transient.
func RetryableExit ¶
RetryableExit reports whether a `message watch` child that ended with this exit status should be restarted (6.6: "restart ... on exit codes 8 and 9 or a crash; stop on 4, 5, 10, 11"). An exit status that is a 4.6 code's is classified as that code (so 8 and 9 restart; 1, 2, 3, 4, 5, 6, 7, 10, 11 and 12 stop); 0 is a clean end and is not a failure to retry; anything else — a signal death (-1 from exec.ExitError.ExitCode(), or 128+n from a shell), 126/127, or a status no code owns — is a crash and restarts. The caller's give-up rule (10 consecutive failures inside 5 minutes) bounds every fast loop this can start: past it the watcher exits, or — for a code Retryable accepts — drops to WatchSlowRetry.
Types ¶
type Schedule ¶
type Schedule struct {
// contains filtered or unexported fields
}
A Schedule yields the delay before each successive attempt. Delay n is drawn uniformly from [base/2, base] where base = min·Factor^n capped at max ("equal jitter"): it never drops below half the minimum, never exceeds the cap, and doubles in expectation until the cap. Reset returns to attempt 0 after a success. A Schedule is not safe for concurrent use; each retry loop owns one.
func AdapterError ¶
AdapterError is the 6.8 schedule for retrying a failed adapter call.
func New ¶
New builds a schedule from minDelay doubling to maxDelay. rng is the jitter source; tests pass rand.New(rand.NewPCG(seed, seed)) for an exact sequence, and nil means a fresh ChaCha8 source seeded from crypto/rand (jitter needs no secrecy, but an unseeded source would make every watcher on a machine retry in lockstep). minDelay must be positive and maxDelay at least minDelay; New clamps rather than panics, because a retry loop is the wrong place to crash.
func WatchRestart ¶
WatchRestart is the 6.6 schedule for restarting the watch child.
func WatchSlow ¶ added in v0.15.0
WatchSlow is the slow retry of the watch child (card 34): a fixed base, so only the jitter varies.
func (*Schedule) Base ¶
Base returns the un-jittered delay of the NEXT attempt: min·Factor^n capped at max. Exposed so a caller can log "retrying in about N s" without consuming the draw.