Skip to content
Permalink
Browse files

Retrying will retry properly on timeouts (#981)

* Fixing bug #947

* Updating tests

* Updating tests

* Refactoring to work with any version

* Update request.go
  • Loading branch information...
xibz committed Dec 12, 2016
1 parent 6545347 commit d5fd6983e17a1644149fb634fdcf69bd03cb8b21
@@ -24,7 +24,7 @@ func TestRequestCancelRetry(t *testing.T) {
s.Handlers.UnmarshalError.Clear()
s.Handlers.Send.PushFront(func(r *request.Request) {
reqNum++
r.Error = errors.New("net/http: canceled")
r.Error = errors.New("net/http: request canceled")
})
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io"
"net"
"net/http"
"net/url"
"reflect"
@@ -297,7 +298,7 @@ func (r *Request) Send() error {

r.Handlers.Send.Run(r)
if r.Error != nil {
if strings.Contains(r.Error.Error(), "net/http: request canceled") {
if !shouldRetryCancel(r) {
return r.Error
}

@@ -364,3 +365,26 @@ func AddToUserAgent(r *Request, s string) {
}
r.HTTPRequest.Header.Set("User-Agent", s)
}

func shouldRetryCancel(r *Request) bool {
awsErr, ok := r.Error.(awserr.Error)
timeoutErr := false
errStr := r.Error.Error()
if ok {
err := awsErr.OrigErr()
netErr, netOK := err.(net.Error)
timeoutErr = netOK && netErr.Temporary()
if urlErr, ok := err.(*url.Error); !timeoutErr && ok {
errStr = urlErr.Err.Error()
}
}

// There can be two types of canceled errors here.
// The first being a net.Error and the other being an error.
// If the request was timed out, we want to continue the retry
// process. Otherwise, return the canceled error.
return timeoutErr ||
(errStr != "net/http: request canceled" &&
errStr != "net/http: request canceled while waiting for connection")

}
@@ -0,0 +1,11 @@
// +build !go1.6

package request_test

import (
"errors"

"github.com/aws/aws-sdk-go/aws/awserr"
)

var errTimeout = awserr.New("foo", "bar", errors.New("net/http: request canceled Timeout"))
@@ -3,11 +3,13 @@
package request_test

import (
"errors"
"testing"

"github.com/stretchr/testify/assert"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/defaults"
@@ -31,3 +33,19 @@ func TestRequestInvalidEndpoint(t *testing.T) {

assert.Error(t, r.Error)
}

type timeoutErr struct {
error
}

var errTimeout = awserr.New("foo", "bar", &timeoutErr{
errors.New("net/http: request canceled"),
})

func (e *timeoutErr) Timeout() bool {
return true
}

func (e *timeoutErr) Temporary() bool {
return true
}
@@ -3,7 +3,6 @@ package request_test
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@@ -313,7 +312,7 @@ func TestRequestRecoverTimeoutWithNilBody(t *testing.T) {
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
}
errors := []error{
errors.New("timeout"), nil,
errTimeout, nil,
}

s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
@@ -349,7 +348,7 @@ func TestRequestRecoverTimeoutWithNilResponse(t *testing.T) {
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
}
errors := []error{
errors.New("timeout"),
errTimeout,
nil,
}

0 comments on commit d5fd698

Please sign in to comment.
You can’t perform that action at this time.