retry

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2023 License: MIT Imports: 5 Imported by: 0

README

Retry

License GoDev Reference Go Report Card

Package retry provides backoff algorithms for retryable processes.

It was inspired by github.com/cenkalti/backoff/v4 which is a port of Google's HTTP Client Library for Java.

Why?

It separates state from policy, which reduces allocations and allows a single policy instance to be used concurrently by all callers, and it uses explicit return values instead of magic sentinel values.

type Policy interface {
    Next(err error, start, now time.Time, attempt int) (backoff time.Duration, retry bool)
}

It decomposes features and encourages their composition.

policy := retry.WithRandomJitter(retry.ConstantBackoff(time.Second), 0.5)

It makes context first-class and improves call ergonomics.

err := retry.Do(ctx, policy, func() error {
    // ...
})

Documentation

Overview

Package retry provides backoff algorithms for retryable processes.

Index

Constants

View Source
const (
	DefaultMinBackoff   = 150 * time.Millisecond
	DefaultMaxBackoff   = 15 * time.Second
	DefaultGrowthFactor = 1.5
	DefaultJitterFactor = 0.5
)

Default policy values.

Variables

This section is empty.

Functions

func Do

func Do(ctx context.Context, policy Policy, fn func() error) error

Do executes the retriable function according to the given policy.

If fn returns a permanent error, the error will be returned without additional retry attempts.

If ctx has a deadline before the next retry attempt would be scheduled it will return the last error without waiting for the deadline.

func DoValue added in v0.2.0

func DoValue[T any](ctx context.Context, policy Policy, fn func() (T, error)) (T, error)

DoValue executes the retriable function according to the given policy and returns the results.

If fn returns a permanent error, the error will be returned without additional retry attempts.

If ctx has a deadline before the next retry attempt would be scheduled it will return the last error without waiting for the deadline.

func NewPermanentError

func NewPermanentError(err error) error

NewPermanentError returns a new error that wraps err and signals that the function should not be retried. If err is nil or is a permanent error already, it's return unchanged.

It's provided as a convenience for simple use cases, but in complex use cases it's probably better to implement permanent error detection as a custom Policy layer.

Types

type Policy

type Policy interface {
	// Next returns the backoff duration to wait before the next attempt
	// and a bool indicating if a retry should be attempted.
	Next(err error, start, now time.Time, attempt int) (backoff time.Duration, retry bool)
}

Policy is a policy for retrying a function.

func ConstantBackoff

func ConstantBackoff(backoff time.Duration) Policy

ConstantBackoff returns a Policy that uses a constant backoff duration.

func DefaultExponentialBackoff

func DefaultExponentialBackoff() Policy

DefaultExponentialBackoff returns an ExponentialBackoff Policy with the default values of min 150ms, max 15s, and factor 150%.

This results in the following behavior:

Attempt    Backoff     Total
      1     0.150s     0.150s
      2     0.225s     0.375s
      3     0.338s     0.713s
      4     0.506s     1.219s
      5     0.759s     1.978s
      6     1.139s     3.117s
      7     1.709s     4.826s
      8     2.563s     7.389s
      9     3.844s    11.233s
     10     5.767s    17.000s
     11     8.650s    25.649s
     12    12.975s    38.624s
     13    15.000s    53.624s
     14    15.000s    68.624s
     15    15.000s    83.624s
    ...      ...        ...

func DefaultPolicy

func DefaultPolicy() Policy

DefaultPolicy returns a Policy using the default exponential backoff with the default random jitter.

This results in the following behavior:

Attempt         Backoff                Total
      1    [0.075s,  0.225s]    [ 0.075s,   0.225s]
      2    [0.113s,  0.338s]    [ 0.188s,   0.562s]
      3    [0.169s,  0.506s]    [ 0.356s,   1.069s]
      4    [0.253s,  0.759s]    [ 0.609s,   1.828s]
      5    [0.380s,  1.139s]    [ 0.989s,   2.967s]
      6    [0.570s,  1.709s]    [ 1.559s,   4.676s]
      7    [0.854s,  2.563s]    [ 2.413s,   7.239s]
      8    [1.281s,  3.844s]    [ 3.694s,  11.083s]
      9    [1.922s,  5.767s]    [ 5.617s,  16.850s]
     10    [2.883s,  8.650s]    [ 8.500s,  25.499s]
     11    [4.325s, 12.975s]    [12.825s,  38.474s]
     12    [6.487s, 19.462s]    [19.312s,  57.936s]
     13    [7.500s, 22.500s]    [26.812s,  80.436s]
     14    [7.500s, 22.500s]    [34.312s, 102.936s]
     15    [7.500s, 22.500s]    [41.812s, 125.436s]
    ...           ...                   ...

func ExponentialBackoff

func ExponentialBackoff(min, max time.Duration, factor float64) Policy

ExponentialBackoff returns a Policy in which the backoff grows exponentially. The backoff will start at the min and will be scaled by the growth factor for each successive attempt until it's capped at the max.

func Immediately

func Immediately() Policy

Immediately returns a Policy that retries with no backoff.

func Never

func Never() Policy

Never returns a Policy that doesn't allow any retry attempts.

func WithDefaultRandomJitter

func WithDefaultRandomJitter(parent Policy) Policy

WithDefaultRandomJitter returns a Policy that wraps the parent Policy with random jitter using the default factor of 50%.

func WithMaxElapsedDuration

func WithMaxElapsedDuration(parent Policy, limit time.Duration) Policy

WithMaxElapsedDuration returns a Policy that wraps the parent Policy and sets a limit for the total elapsed duration in which retries are allowed.

func WithMaxRetries

func WithMaxRetries(parent Policy, limit int) Policy

WithMaxRetries returns a Policy that wraps the parent Policy and sets a limit for the total number of retry attempts.

func WithRandomJitter

func WithRandomJitter(parent Policy, factor float64) Policy

WithRandomJitter returns a Policy that wraps the parent Policy and adds or subtracts random jitter as a factor of its backoff. For example, with a factor of 0.5 and a parent backoff of 10s, the randomized backoff would be in [5s, 15s].

Jump to

Keyboard shortcuts

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