Reputation: 3412
In my go application I am getting the following error: "http: server closed idle connection". I would like to catch it and retry my http connection if it's encountered.
I found that this error comes from the "net/http" package and furthermore from the transport implementation. In particular it's defined here
I get it wrapped in url.Error
but this is all I was able to find out. Do you know how I can actually catch this error?
Edit:
I am using elastic search client, which in turn is using the net/http
. From the client I get the above mentioned error and would like to retry my elastic search request as being transient. For now the way I am catching transient errors is:
if urlErr, ok := err.(*url.Error); ok && (urlErr.Temporary() || urlErr.Err == io.EOF) {
return retryRequest()
}
Upvotes: 8
Views: 7617
Reputation: 2703
As Gray Fox mentioned, Go will usually retry these requests. However, this is not the case for requests that aren't "idempotent". I was running into a few of these errors on POST
requests, and after searching around I found this Github issue that says:
The HTTP Transport would normally retry those requests, but because they're POST requests they're not idempotent and Go conservatively assumes it might be unsafe to retry them.
Later in the issue someone mentioned that many banking APIs use some variant of the Idempotent-Key
header to make them "safe". Stripe is a company that uses that header, and this is what their API docs say about it:
The API supports idempotency for safely retrying requests without accidentally performing the same operation twice.
So there you go, that's what the header is for.
In short, if you want Go's HTTP Transport to retry POST requests (and other non-idempotent requests), you need to include either the Idempotency-Key
or X-Idempotency-Key
header. That doesn't necessarily make those requests idempotent, but it will make them retry-able from net/http
's perspective.
Links:
Upvotes: 4
Reputation: 673
Comments in net/http/transport.go
say this (located here):
if err == errServerClosedIdle {
// The server replied with io.EOF while we were trying to
// read the response. Probably an unfortunately keep-alive
// timeout, just as the client was writing a request.
return true
}
Go will attempt to retry the request if it finds a non-nil http.Request.GetBody
(found here), so I think it is expected to retry the request (or provide a GetBody
function).
As for the leading error cause, you might want to check server's keep-alive functionality, my guess is that server is sending TCP connection reset (interpreted as io.EOF
) prematurely. You might want to try disabling keep-alives and see if that changes anything.
Upvotes: 5