> On 7 Dec 2020, at 10:58 pm, 'Axel Wagner' via golang-nuts <
golan...@googlegroups.com> wrote:
>
> We recently had the same issue.
>
> On Mon, Dec 7, 2020 at 11:58 AM Gregor Best <
be...@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 (
> 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.