Skip to content
Snippets Groups Projects
Commit 1fd8c2e2 authored by ale's avatar ale
Browse files

Modify the temporary error interface for Retry

Now the default is for errors to be permanent, unless the error itself
has a Temporary() method that returns true (like the transient network
errors do in the net/ package).
parent 96dc5502
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,6 @@ package clientutil
import (
"errors"
"net"
"net/http"
"time"
......@@ -18,14 +17,37 @@ func NewExponentialBackOff() *backoff.ExponentialBackOff {
return b
}
// Retry operation op until it succeeds according to the backoff policy b.
// A temporary (retriable) error is something that has a Temporary method.
type tempError interface {
Temporary() bool
}
type tempErrorWrapper struct {
error
}
func (t tempErrorWrapper) Temporary() bool { return true }
// TempError makes a temporary (retriable) error out of a normal error.
func TempError(err error) error {
return tempErrorWrapper{err}
}
// Retry operation op until it succeeds according to the backoff
// policy b.
//
// Note that this function reverses the error semantics of
// backoff.Operation: all errors are permanent unless explicitly
// marked as temporary (i.e. they have a Temporary() method that
// returns true). This is to better align with the errors returned by
// the net package.
func Retry(op backoff.Operation, b backoff.BackOff) error {
innerOp := func() error {
err := op()
if err == nil {
return err
}
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
if tmpErr, ok := err.(tempError); ok && tmpErr.Temporary() {
return err
}
return backoff.Permanent(err)
......@@ -33,7 +55,7 @@ func Retry(op backoff.Operation, b backoff.BackOff) error {
return backoff.Retry(innerOp, b)
}
var errHTTPBackOff = errors.New("temporary http error")
var errHTTPBackOff = TempError(errors.New("temporary http error"))
func isStatusTemporary(code int) bool {
switch code {
......@@ -46,7 +68,8 @@ func isStatusTemporary(code int) bool {
// RetryHTTPDo retries an HTTP request until it succeeds, according to
// the backoff policy b. It will retry on temporary network errors and
// upon receiving specific temporary HTTP errors.
// upon receiving specific temporary HTTP errors. It will use the
// context associated with the HTTP request object.
func RetryHTTPDo(client *http.Client, req *http.Request, b backoff.BackOff) (*http.Response, error) {
var resp *http.Response
op := func() error {
......@@ -64,6 +87,6 @@ func RetryHTTPDo(client *http.Client, req *http.Request, b backoff.BackOff) (*ht
return err
}
err := Retry(op, b)
err := Retry(op, backoff.WithContext(b, req.Context()))
return resp, err
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment