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 RetryAfterHTTP ¶
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 ¶
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 ¶
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 ¶
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 ¶
Err returns the reason for terminating the backoff, or nil if it didn't terminate
func (*Backoff) NumRetries ¶
NumRetries returns the number of retries so far
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 ¶
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: