Close client connection on backend TCP failure

Hello,

I’m setting up a file upload, but I have trouble closing connections when the backend restarts.

My current setup is HAProxy > Frankenphp (dockerized).

  • When I restart HAProxy, the client connection is closed as expected and receives a NS_ERROR_CONNECTION_REFUSED on Firefox :white_check_mark:

  • When I restart Franken, the client connection is not properly closed and the client keeps trying sending data :cross_mark:

I have to restart Franken sometimes during new deployments. I don’t mind interrupting client uploads, but I’d like to give them proper error messages.

Franken is restarted with docker compose up -d --force-recreate franken, so no graceful shutdown or Connection: close header sent by the server.

Here is my HAProxy 3.1 configuration:

defaults
    timeout connect 1s
    timeout client 30s
    timeout server 10s

frontend www
    bind :80
    mode http
    default_backend franken

backend franken
    mode http
    option httpchk GET /healthcheck.php
    http-check expect string OK
    option forwardfor except 127.0.0.1
    server franken1 franken:80 check

How to close the client connection, if the backend TCP connection fails and not closed properly?

I tried using http checks, but the restart can be very fast.

Any idea on this matter? Let me know if more context/logs/setup is needed.

Thanks by advance!

Without proper shutdown, it will take timeout server amount of time to close the session.

Some suggestions:

But if the backend just vanishes, there is not indication for haproxy to react, all you have are timeouts (and this should only happen with a catastrophic HW failure; if you are specifically killing a container instead of properly shutting it down, that leads to the same behaviour as a catastrophic HW failure I guess).

Thanks for your answer!

So instead of restarting the container, I’m trying to stop it gracefully:

docker compose exec franken frankenphp stop

With the health check configured, HAProxy marks it down as expected:

haproxy-1 | Server franken/franken1 is DOWN, reason: Layer7 timeout, check duration: 2003ms. 0 active and 0 backup servers left. 1 sessions active, 0 requeued, 0 remaining in queue.
haproxy-1 | backend franken has no server available!
haproxy-1 | [WARNING] (8) : Server franken/franken1 is DOWN, reason: Layer7 timeout, check duration: 2003ms. 0 active and 0 backup servers left. 1 sessions active, 0 requeued, 0 remaining in queue.
haproxy-1 | [ALERT] (8) : backend ‘franken’ has no server available!

And logs a 500 error:

172.20.0.1:41902 [21/Oct/2025:09:15:01.660] www franken/franken1 0/0/0/-1/21405 500 0 - - DC-- 8/8/0/0/0 0/0 “POST /upload HTTP/1.1”

But the client is still sending the request and didn’t receive the error.
Any idea what could be missing?

Here is the updated config I’m now using:

defaults
    timeout connect 1s
    timeout client 30s
    timeout server 10s
    option abortonclose

frontend www
    bind :80
    mode http
    default_backend franken

backend franken
    mode http
    option httpchk GET /healthcheck.php
    http-check expect string OK
    option forwardfor except 127.0.0.1
    server franken1 franken:80 check on-marked-down shutdown-sessions

I think I’m getting closer, thanks for your help again :folded_hands:

Capturing the front and backend traffic while this happens and taking a look at it would be most helpful.

Depending on how you come to this conclusion, the client may receive the error but keep on pushing data. Taking a look at what happens on the wire would be most helpful.

Right, I came to this conclusion because the browser receive a catchable error when HAProxy is restarted, but not when Franken is!

Capturing the front and backend traffic while this happens and taking a look at it would be most helpful.

Is there a debugging HAProxy tool to do that?

No, you’d use basic tcpdump for that in this case.

1 Like

Hi,

Turned out the issue was on the file upload JavaScript library. I didn’t expect that.
Using curl, the connection was closed as expected, and changing the file upload library resolved the issue and a proper error is shown to the client.

Thanks for your help! It allowed me to understand better HAProxy, and optimize my configuration.

1 Like