Skip to content

Commit 86d5201

Browse files
committed
Issue #23: Request should be retried also on ECONNABORTED and ECONNREFUSED
1 parent 943333d commit 86d5201

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

request.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func Send(options *Options, results interface{}) (*Content, error) {
120120
log = log.Record("duration", reqDuration/time.Millisecond)
121121
if err != nil {
122122
netErr := &net.OpError{}
123-
if errors.As(err, &netErr) && errors.Is(netErr, syscall.ECONNRESET) {
123+
if errors.As(err, &netErr) && (errors.Is(netErr, syscall.ECONNRESET) || errors.Is(netErr, syscall.ECONNABORTED) || errors.Is(netErr, syscall.ECONNREFUSED)) {
124124
if attempt+1 < options.Attempts {
125125
log.Warnf("Temporary failed to send request (duration: %s/%s), Error: %s", reqDuration, options.Timeout, err.Error()) // we don't want the stack here
126126
log.Infof("Waiting for %s before trying again", options.InterAttemptDelay)

request_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"encoding/json"
77
"fmt"
8+
"net"
89
"net/http"
910
"net/http/httptest"
1011
"net/url"
@@ -717,6 +718,52 @@ func (suite *RequestSuite) TestCanRetryReceivingRequestECONNRESET() {
717718
suite.Require().NoError(err, "Failed reading response content, err=%+v", err)
718719
}
719720

721+
func (suite *RequestSuite) TestCanRetryReceivingRequestECONNREFUSED() {
722+
// Start the client in a separate goroutine
723+
go func() {
724+
serverURL, _ := url.Parse("http://localhost:1234")
725+
response, err := request.Send(&request.Options{
726+
URL: serverURL,
727+
Attempts: 2,
728+
Timeout: 1 * time.Second,
729+
Logger: suite.Logger,
730+
}, nil)
731+
suite.Require().NoError(err, "Failed reading response content, err=%+v", err)
732+
suite.Assert().Equal("body", string(response.Data))
733+
}()
734+
735+
listener, err := net.Listen("tcp", ":1234")
736+
suite.Require().NoError(err, "Failed starting the listener")
737+
listener.Close() // that will cause the ECONNREFUSED
738+
time.Sleep(2 * time.Second)
739+
740+
listener, err = net.Listen("tcp", ":1234")
741+
suite.Require().NoError(err, "Failed starting the listener")
742+
defer listener.Close()
743+
744+
// accept the connection
745+
conn, err := listener.Accept()
746+
suite.Require().NoError(err, "Failed accepting the connection")
747+
defer conn.Close()
748+
749+
_, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nbody"))
750+
time.Sleep(1 * time.Second)
751+
}
752+
753+
func (suite *RequestSuite) TestCanRetryReceivingRequestECONNABORTED() {
754+
server := CreateEConnAbortedTestServer(suite, 3)
755+
defer server.Close()
756+
757+
serverURL, _ := url.Parse(server.URL)
758+
_, err := request.Send(&request.Options{
759+
URL: serverURL,
760+
Attempts: 5,
761+
Timeout: 1 * time.Second,
762+
Logger: suite.Logger,
763+
}, nil)
764+
suite.Require().NoError(err, "Failed reading response content")
765+
}
766+
720767
func (suite *RequestSuite) TestCanRetryReceivingRequestEOF() {
721768
serverURL, _ := url.Parse(suite.Server.URL)
722769
serverURL, _ = serverURL.Parse("/retry_eof")

server_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -428,3 +428,17 @@ func CreateEConnResetTestServer(suite *RequestSuite, maxResets int) *httptest.Se
428428
testserver.Start()
429429
return testserver
430430
}
431+
432+
func CreateEConnAbortedTestServer(suite *RequestSuite, failAttempts int) *httptest.Server {
433+
attempts := 0
434+
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
435+
if attempts < failAttempts {
436+
attempts++
437+
conn, _, _ := w.(http.Hijacker).Hijack()
438+
conn.Close() // This will cause ECONNABORTED
439+
return
440+
}
441+
w.WriteHeader(http.StatusOK)
442+
_, _ = w.Write([]byte("OK"))
443+
}))
444+
}

0 commit comments

Comments
 (0)