> On 7 Dec 2020, at 10:58 pm, 'Axel Wagner' via golang-nuts 
> <golang-nuts@googlegroups.com> wrote:
> 
> We recently had the same issue.
> 
> On Mon, Dec 7, 2020 at 11:58 AM Gregor Best <b...@pferdewetten.de> wrote:
> Hi!
> 
> We're using a 3rd party provider's API to handle some of our customer
> requests. Interaction with their API consists of essentially POST'ing
> a small XML document to them.
> 
>  From time to time, `net/http`'s `Client.Do` returns an `io.EOF`
> when sending the request. For now, the provider always reported
> those instances as "we didn't get your request".
> 
> Cursory search in various Github issues and a glance at the source
> of `net/http` seems to indicate that `io.EOF` is almost always
> caused by the server closing the connection, but the client not
> getting the "it's now closed" signal before it tries to re-use the
> connection.
> 
> That was what I concluded as well. I think it could theoretically also happen 
> if a new connection is opened and immediately closed by the server.
> 
> FWIW, `fasthttp`'s HTTP client implementation treats `io.EOF` as
> "this request needs to be retried", but I don't know how much that
> knowledge transfers to `net/http`.
> 
> I think `fasthttp` is behaving incorrectly - in particular, if it also does 
> so for POST requests (you mention that you use them). They are, in general, 
> not idempotent and there is a race where the client sends the request, the 
> server receives it and starts handling it (causing some observable 
> side-effects) but then dies before it can send a response, with the 
> connection being closed by the kernel. If the client retries that (at a 
> different backend, or once the server got restarted), you might end up with 
> corrupted state.
> 
> AIUI, `net/http` never assumes requests are retriable - even GET requests - 
> and leaves it up to the application to decide, whether a request can be 
> retried or not. Our solution was to verify that all our requests *can* be 
> retried and then wrapping the client call with retries.

Just wanted to point out here that the standard Transport has some retry 
behaviour by default (https://golang.org/pkg/net/http/#Transport):

> Transport only retries a request upon encountering a network error if the 
> request is idempotent and either has no body or has its Request.GetBody 
> defined. HTTP requests are considered idempotent if they have HTTP methods 
> GET, HEAD, OPTIONS, or TRACE; or if their Header map contains an 
> "Idempotency-Key" or "X-Idempotency-Key" entry. If the idempotency key value 
> is a zero-length slice, the request is treated as idempotent but the header 
> is not sent on the wire.




-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/5AC3D229-BDFD-490A-93DA-3822C5BE80B0%40gmail.com.

Reply via email to