Skip to content

Commit

Permalink
Add RetryError
Browse files Browse the repository at this point in the history
- Exposes additional information such as request and status code
  to help determine (via a Predicate) whether the RoundTripper should retry or not

Authored-by: Dennis Leon <leonde@vmware.com>
  • Loading branch information
DennisDenuto committed Sep 10, 2021
1 parent 6a5f6b3 commit cfea68c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
49 changes: 47 additions & 2 deletions pkg/v1/remote/transport/retry.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package transport

import (
"context"
"net/http"
"time"

Expand Down Expand Up @@ -49,7 +50,7 @@ type options struct {
// Backoff is an alias of retry.Backoff to expose this configuration option to consumers of this lib
type Backoff = retry.Backoff

// This is implemented by several errors in the net package as well as our
// Temporary is implemented by several errors in the net package as well as our
// transport.Error
type Temporary interface {
Temporary() bool
Expand Down Expand Up @@ -87,10 +88,54 @@ func NewRetry(inner http.RoundTripper, opts ...Option) http.RoundTripper {
}
}

// RetryError is an error returned by retryTransport. Exposes additional information such as request and status code
// to help determine (via a Predicate) whether the RoundTripper should retry or not.
type RetryError struct {
Inner error
// The http status code returned.
StatusCode int
// The request that failed.
Request *http.Request
}

// Temporary delegates to the wrapped error if it exists
func (e *RetryError) Temporary() bool {
if te, ok := e.Inner.(Temporary); ok && te.Temporary() {
return true
}

return false
}

// Check that RetryError implements error
var _ error = (*RetryError)(nil)

func (e *RetryError) Error() string {
if e.Inner != nil {
return e.Inner.Error()
}

return ""
}

func (t *retryTransport) RoundTrip(in *http.Request) (out *http.Response, err error) {
roundtrip := func() error {
out, err = t.inner.RoundTrip(in)
return err

if err == context.DeadlineExceeded {
return err
}

var statusCode int
if out != nil {
statusCode = out.StatusCode
}

return &RetryError{
Inner: err,
StatusCode: statusCode,
Request: in,
}
}
retry.Retry(roundtrip, t.predicate, t.backoff)
return
Expand Down
1 change: 1 addition & 0 deletions pkg/v1/remote/transport/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ type Transport struct {
inner http.RoundTripper
}

// RoundTrip delegates to the inner RoundTripper
func (t *Transport) RoundTrip(in *http.Request) (*http.Response, error) {
return t.inner.RoundTrip(in)
}

0 comments on commit cfea68c

Please sign in to comment.