Skip to content

Retry Policy EN

sungaowei edited this page Oct 16, 2026 · 1 revision

Retry Policy

English | 简体中文


Retries are enabled by default. DefaultRetryPolicy() returns:

Field Default Meaning
MaxRetries 2 Retries after the initial attempt. 0 disables retries.
BackoffInitial 500ms First backoff delay; doubles per attempt up to BackoffMax. 0 disables backoff.
BackoffMax 5s Cap on a single backoff delay.
BackoffJitter 0.25 Fraction of each delay randomly subtracted, between 0 and 1.
HTTPStatuses 408, 429, and every 5xx (including 529) Status codes that are retried. Built by DefaultRetryStatuses().
RespectRetryAfter true Honors retry-after-ms and Retry-After (seconds or HTTP date).
APIConnectionError true Retries failures that never produced an HTTP response.
APITimeoutError true Retries requests that exceeded their attempt timeout.
RetryErrors nil Extra sentinel errors that trigger a retry; matched with errors.Is.
Predicate nil func(error) bool consulted for every failure; true triggers a retry.
Timeout 30s (DefaultRetryBudget) Total budget for one call, covering the initial attempt, retries, and delays. A retry whose delay would reach the budget is abandoned and the last error is returned. nil disables the budget.
Sleep nil Seam for tests: func(ctx, delay) error replaces the context-aware timer.
RandFloat nil Seam for tests: func() float64 in [0, 1) replaces the jitter source.

Customizing

Start from the default and adjust, or set only the fields you care about:

policy := typesafe.DefaultRetryPolicy()
policy.MaxRetries = 4
policy.BackoffInitial = 250 * time.Millisecond
policy.Timeout = new(15 * time.Second)

client, err := typesafe.NewClient(typesafe.WithRetryPolicy(policy))

Retrying Your Own Errors

RetryErrors and Predicate extend the decision to failures the SDK does not raise:

policy := typesafe.DefaultRetryPolicy()
policy.RetryErrors = []error{myErrTransient}
policy.Predicate = func(err error) bool { return isRetryableByMyRules(err) }

Behavior

  • Attempt count. MaxRetries = N means at most N + 1 attempts.
  • Backoff. The first retry waits BackoffInitial; each subsequent retry doubles it, capped at BackoffMax, then a random BackoffJitter fraction is subtracted. Delays are rounded to the millisecond.
  • Retry-After wins. When RespectRetryAfter is set and the response carries retry-after-ms or Retry-After, the server's delay is used as-is: it is not capped by BackoffMax and not jittered.
  • Budget. With Timeout set, a retry whose delay would reach or exceed the remaining budget is abandoned and the last error is returned.
  • Cancellation is final. A cancelled or expired context is never retried.
  • Traceability. Each retry carries the X-TypeSafe-Retry-Count header (1 for the first retry, 2 for the second, …). A caller-supplied value is stripped.

Other Entry Points

err := policy.Validate()   // report a malformed policy
copy := policy.Clone()     // deep copy, e.g. to tweak one field per call
err = policy.Execute(ctx, func(attempt int) error {
	// run fn under the policy
})

Disabling Retries

policy := typesafe.DefaultRetryPolicy()
policy.MaxRetries = 0

Clone this wiki locally