<div dir="ltr"><div>Hi Maxim,</div><div><br></div><div>I finally decided to activate retries of non idempotent requests, cause I already manage data deduplication.</div><div><br></div><div>Now I have: proxy_next_upstream error timeout invalid_header http_502 http_504 non_idempotent;</div><div><br></div><div>Nevertheless I still see the same error messages when I trigger a reload of an nginx in upstream.</div><div>Does it mean the problem is that same, or just that nginx (the ones in front) still displays such error messages for information, but has effectively retried the request on another server in upstream?</div><div><br></div><div>Kind regards,</div><div><br></div><div>Sébastien.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le lun. 25 mars 2024 à 16:40, Sébastien Rebecchi <<a href="mailto:srebecchi@kameleoon.com">srebecchi@kameleoon.com</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Thank you Maxim for that comprehensive explanation.<div>I will think about non_idempotent then, and wait for an eventual release of freenginx that natively solves that issue :)</div><div>Have a great day</div><div>Sébastien.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le lun. 25 mars 2024 à 16:20, Maxim Dounin <<a href="mailto:mdounin@mdounin.ru" target="_blank">mdounin@mdounin.ru</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hello!<br>
<br>
On Mon, Mar 25, 2024 at 01:31:26PM +0100, Sébastien Rebecchi wrote:<br>
<br>
> I have an issue with nginx closing prematurely connections when reload is<br>
> performed.<br>
> <br>
> I have some nginx servers configured to proxy_pass requests to an upstream<br>
> group. This group itself is composed of several servers which are nginx<br>
> themselves, and is configured to use keepalive connections.<br>
> <br>
> When I trigger a reload (-s reload) on an nginx of one of the servers which<br>
> is target of the upstream, I see in error logs of all servers in front that<br>
> connection was reset by the nginx which was reloaded.<br>
<br>
[...]<br>
<br>
> And here the kind of error messages I get when I reload nginx of "IP_1":<br>
> <br>
> --- BEGIN ---<br>
> <br>
> 2024/03/25 11:24:25 [error] 3758170#0: *1795895162 recv() failed (104:<br>
> Connection reset by peer) while reading response header from upstream,<br>
> client: CLIENT_IP_HIDDEN, server: SERVER_HIDDEN, request: "POST<br>
> /REQUEST_LOCATION_HIDDEN HTTP/2.0", upstream: "<br>
> <a href="http://IP_1:80/REQUEST_LOCATION_HIDDEN" rel="noreferrer" target="_blank">http://IP_1:80/REQUEST_LOCATION_HIDDEN</a>", host: "HOST_HIDDEN", referrer:<br>
> "REFERRER_HIDDEN"<br>
> <br>
> --- END ---<br>
> <br>
> <br>
> I thought -s reload was doing graceful shutdown of connections. Is it due<br>
> to the fact that nginx can not handle that when using keepalive<br>
> connections? Is it a bug?<br>
> <br>
> I am using nginx 1.24.0 everywhere, no particular<br>
<br>
This looks like a well known race condition when closing HTTP <br>
connections.  In RFC 2616, it is documented as follows<br>
(<a href="https://datatracker.ietf.org/doc/html/rfc2616#section-8.1.4" rel="noreferrer" target="_blank">https://datatracker.ietf.org/doc/html/rfc2616#section-8.1.4</a>):<br>
<br>
   A client, server, or proxy MAY close the transport connection at any<br>
   time. For example, a client might have started to send a new request<br>
   at the same time that the server has decided to close the "idle"<br>
   connection. From the server's point of view, the connection is being<br>
   closed while it was idle, but from the client's point of view, a<br>
   request is in progress.<br>
<br>
   This means that clients, servers, and proxies MUST be able to recover<br>
   from asynchronous close events. Client software SHOULD reopen the<br>
   transport connection and retransmit the aborted sequence of requests<br>
   without user interaction so long as the request sequence is<br>
   idempotent (see section 9.1.2). Non-idempotent methods or sequences<br>
   MUST NOT be automatically retried, although user agents MAY offer a<br>
   human operator the choice of retrying the request(s). Confirmation by<br>
   user-agent software with semantic understanding of the application<br>
   MAY substitute for user confirmation. The automatic retry SHOULD NOT<br>
   be repeated if the second sequence of requests fails.<br>
<br>
That is, when you shutdown your backend server, it closes the <br>
keepalive connection - which is expected to be perfectly safe from <br>
the server point of view.  But if at the same time a request is <br>
being sent to this connection by the client (frontend nginx server <br>
in your case) - this might result in an error.<br>
<br>
Note that the race is generally unavoidable and such errors can <br>
happen at any time, during any connection close by the server.  <br>
Closing multiple keepalive connections during shutdown makes such <br>
errors more likely though, since connections are closed right <br>
away, and not after keepalive timeout expires.  Further, since in <br>
your case there are just a few loaded keepalive connections, this <br>
also makes errors during shutdown more likely.<br>
<br>
Typical solution is to retry such requests, as RFC 2616 <br>
recommends.  In particular, nginx does so based on the <br>
"proxy_next_upstream" setting.  Note that to retry POST requests <br>
you will need "proxy_next_upstream ... non_idempotent;" (which <br>
implies that non-idempotent requests will be retried on errors, <br>
and might not be the desired behaviour).<br>
<br>
Another possible approach is to try to minimize the race window by <br>
waiting some time after the shutdown before closing keepalive <br>
connections.  There were several attempts in the past to implement <br>
this, the last one can be found here:<br>
<br>
<a href="https://mailman.nginx.org/pipermail/nginx-devel/2024-January/YSJATQMPXDIBETCDS46OTKUZNOJK6Q22.html" rel="noreferrer" target="_blank">https://mailman.nginx.org/pipermail/nginx-devel/2024-January/YSJATQMPXDIBETCDS46OTKUZNOJK6Q22.html</a><br>
<br>
While there are some questions to the particular patch, something <br>
like this should probably be implemented.<br>
<br>
This is my TODO list, so a proper solution should be eventually <br>
available out of the box in upcoming freenginx releases.<br>
<br>
Hope this helps.<br>
<br>
-- <br>
Maxim Dounin<br>
<a href="http://mdounin.ru/" rel="noreferrer" target="_blank">http://mdounin.ru/</a><br>
-- <br>
nginx mailing list<br>
<a href="mailto:nginx@freenginx.org" target="_blank">nginx@freenginx.org</a><br>
<a href="https://freenginx.org/mailman/listinfo/nginx" rel="noreferrer" target="_blank">https://freenginx.org/mailman/listinfo/nginx</a><br>
</blockquote></div>
</blockquote></div></div>