> 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.