backoff

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2020 License: Apache-2.0, Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package backoff implements a convenient mechanism to retry an operation. This is useful when talking to a remote system (database, third-party integration) that can fail for any reason (e.g. network), and where a retry would usually solve the issue.

Example
package main

import (
	"context"
	"errors"
	"log"
	"time"

	"github.com/engage-ehs/kit/backoff"
)

func main() {
	// The number of retries can be limited using a context
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
	defer cancel()

	// The number of retries can also be limited by the number of operations
	retry := backoff.New(ctx, 10)
	for retry.Ongoing() {
		err := doremotecall()
		if !shouldretry(err) {
			return
		}
		retry.Wait()
	}

	log.Println(retry.Err())
}

func doremotecall() error {
	// here is the remote call operation, potentially failing
	return nil
}

type NetworkError struct {
	ShouldRetry bool
	Underlying  error
}

func (e NetworkError) Error() string { return e.Underlying.Error() }

func shouldretry(err error) bool {
	if err == nil {
		return false
	}

	var ne NetworkError
	if errors.As(err, &ne) {
		return ne.ShouldRetry
	}
	return false
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Register

func Register(b Backoff, name string)

Register exports a backoff so it will be scraped by Prometheus

func RetryAfterHTTP

func RetryAfterHTTP(rsp *http.Response) time.Duration

RetryAfter reads HTTP headers to see if a duration was provided as an HTTP “retry-after” header (RFC 7231, section 7.1.3: Retry-After). It handles both absolute and relative dates.

func ShouldRetryHTTP

func ShouldRetryHTTP(rsp *http.Response) bool

ShouldRetryHTTP can be used to know if a retry is a reasonable strategy to deal with an HTTP error (429 or 5xx code).

func ShouldRetryPostgreSQL

func ShouldRetryPostgreSQL(err error) bool

ShouldRetryPostgreSQL can be used to know if a retry is a reasonable strategy to deal with a PostgreSQL error.

Types

type Backoff

type Backoff struct {
	MaxRetries int
	// contains filtered or unexported fields
}

Backoff implements exponential backoff with randomized wait times. It is not safe to share a Backoff structure between multiple goroutines.

func New

func New(ctx context.Context, retries int) *Backoff

New creates a Backoff object that terminates either when the context terminates (built-in timeout), or when the maximum number of retries is reached. Passing no maximum number of retries means infinite number, in which case the context deadline is used, or a deadline of 2 minutes is chosen by default.

func (*Backoff) Err

func (b *Backoff) Err() error

Err returns the reason for terminating the backoff, or nil if it didn't terminate

func (*Backoff) NextDelay

func (b *Backoff) NextDelay() time.Duration

func (*Backoff) NumRetries

func (b *Backoff) NumRetries() int

NumRetries returns the number of retries so far

func (*Backoff) Ongoing

func (b *Backoff) Ongoing() bool

Ongoing returns true if caller should keep going

func (*Backoff) Wait

func (b *Backoff) Wait()

Wait sleeps for the backoff time then increases the retry count and backoff time Returns immediately if Context is terminated

func (*Backoff) WaitFor

func (b *Backoff) WaitFor(d time.Duration)

WaitFor can be used to wait for a specific duration, for example if the duration is provided by the remote API. Calling this method does increase the backoff, just like a regular Wait call.

Example
var apierr error

retry := New(context.Background(), 10)
for retry.Ongoing() {
	rsp, err := http.Get("http://example.net/myapi")
	if err != nil {
		apierr = err
		break
	}
	if rsp.StatusCode != http.StatusOK && !ShouldRetryHTTP(rsp) {
		apierr = errors.New("Unexpected status code " + rsp.Status)
		break
	}
	retry.WaitFor(RetryAfterHTTP(rsp))
}

log.Println(apierr)
Output:

Jump to

Keyboard shortcuts

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