MINOR: proxy: explicitly permit abortonclose on frontends and clarify the doc

The "abortonclose" option was recently deprecated in frontends because its
action was essentially limited to the backend part (queuing etc). But in
3.3 we started to support it for TLS on frontends, though it would only
work when placed in a defaults section. Let's officially support it in
frontends, and take this opportunity to clarify the documentation on this
topic, which was incomplete regarding frontend and TLS support. Now the
doc tries to better cover the different use cases.
This commit is contained in:
Willy Tarreau 2025-10-08 08:34:43 +02:00
parent f657ffc6e7
commit c42e62d890
2 changed files with 43 additions and 33 deletions

View File

@ -5571,7 +5571,7 @@ maxconn X X X -
mode X X X X mode X X X X
monitor fail - X X - monitor fail - X X -
monitor-uri X X X - monitor-uri X X X -
option abortonclose (*) X - X X option abortonclose (*) X X X X
option allbackups (*) X - X X option allbackups (*) X - X X
option checkcache (*) X - X X option checkcache (*) X - X X
option clitcpka (*) X X X - option clitcpka (*) X X X -
@ -9044,46 +9044,56 @@ monitor-uri <uri>
option abortonclose option abortonclose
no option abortonclose no option abortonclose
Enable or disable early dropping of aborted requests pending in queues. Enable or disable early abortion of not started processing when client closes
May be used in the following contexts: tcp, http May be used in the following contexts: tcp, http
May be used in sections : defaults | frontend | listen | backend May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes yes | yes | yes | yes
Arguments : none Arguments : none
In presence of very high loads, the servers will take some time to respond. TCP connections support being closed independently in each direction, and a
The per-instance connection queue will inflate, and the response time will connection with only one direction closed is often said to be "half-closed".
increase respective to the size of the queue times the average per-stream Originally when the HTTP ecosystem was mostly made of the "close mode", with
response time. When clients will wait for more than a few seconds, they will only one request and one response per connection before closing, it was
often hit the "STOP" button on their browser, leaving a useless request in pretty frequent to see scripted clients send their request, close the sending
the queue, and slowing down other users, and the servers as well, because the side, wait for the response, receive the close indication and be done with
request will eventually be served, then aborted at the first error this. But with the arrival of keep-alive and more advanced protocols, this
encountered while delivering the response. practice has practically disappeared and the only cases where a client closes
before receiving its response is essentially when the user wants to abort a
transfer, or when a timeout strikes and the connection is closed.
As there is no way to distinguish between a full STOP and a simple output These two situations (half-closed vs abort) are undistinguishable from the
close on the client side, HTTP agents should be conservative and consider server side (here the HAProxy listener). This is a problem because leaving
that the client might only have closed its output channel while waiting for the connection alive and continuing to process a request when clients abort
the response. However, this introduces risks of congestion when lots of users can cost a lot of resources, particularly if the closure is the result of a
do the same, and is completely useless nowadays because probably no client at user hitting the "reload" button, as it means new requests are queued without
all will close the stream while waiting for the response. Some HTTP agents the previous ones being aborted. And conversely, systematically aborting when
support this behavior (Squid, Apache, HAProxy), and others do not (TUX, most facing such a half-close situation would break a number of TCP applications
hardware-based load balancers). So the probability for a closed input channel and even some HTTP ones on internal networks interacting with legacy agents.
to represent a user hitting the "STOP" button is close to 100%, and the risk
of being the single component to break rare but valid traffic is extremely
low, which adds to the temptation to be able to abort a stream early while
still not served and not pollute the servers.
In HAProxy, the user can choose the desired behavior using the option The "abortonclose" option permits to choose the desired behavior:
"abortonclose". By default (without the option) the behavior is HTTP - when present in a frontend, it will avoid processing TLS handshakes which
compliant and aborted requests will be served. But when the option is are pending on a half-closed connection. This can be the result of a user
specified, a stream with an incoming channel closed will be aborted while hitting "reload" during an HTTPS request under high load such as a VRRP
it is still possible, either pending in the queue for a connection slot, or fail-over between an active HAProxy node and the backup one: all clients
during the connection establishment if the server has not yet acknowledged reconnect at the same time to the new node, and all have to perform a
the connection request. This considerably reduces the queue size and the load costly, full TLS handshake. If it takes more than a few seconds, it's
on saturated servers when users are tempted to click on STOP, which in turn likely that some users will give up, and it's pointless to waste CPU
reduces the response time for other users. cycles on their handshakes. Given the CPU cost of TLS handshakes, it is
recommended to leave this option enabled on internet-facing frontends.
- when present in a backend, it will cause half-closed connections to try
to abort a request that was not yet sent to a server (i.e. when it's
pending in the queue or when trying to connect). If the request is
already being served by a server, then the connection to the server is
in turn switched to half-close to indicate the same condition to the
server, which will then decide how to proceed.
The recommendation is to enable this option on internet-facing TLS endpoints
and HTTP services, and to disable it for pure TCP ones as well as unexposed
legacy environments.
If this option has been enabled in a "defaults" section, it can be disabled If this option has been enabled in a "defaults" section, it can be disabled
in a specific instance by prepending the "no" keyword before it. in a specific instance by prepending the "no" keyword before it.

View File

@ -82,7 +82,7 @@ struct show_srv_ctx {
/* proxy->options */ /* proxy->options */
const struct cfg_opt cfg_opts[] = const struct cfg_opt cfg_opts[] =
{ {
{ "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0, 0 }, { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE|PR_CAP_FE, 0, 0 },
{ "allbackups", PR_O_USE_ALL_BK, PR_CAP_BE, 0, 0 }, { "allbackups", PR_O_USE_ALL_BK, PR_CAP_BE, 0, 0 },
{ "checkcache", PR_O_CHK_CACHE, PR_CAP_BE, 0, PR_MODE_HTTP }, { "checkcache", PR_O_CHK_CACHE, PR_CAP_BE, 0, PR_MODE_HTTP },
{ "clitcpka", PR_O_TCP_CLI_KA, PR_CAP_FE, 0, 0 }, { "clitcpka", PR_O_TCP_CLI_KA, PR_CAP_FE, 0, 0 },