ninenines / cowboy

Small, fast, modern HTTP server for Erlang/OTP.
https://ninenines.eu
ISC License
7.25k stars 1.16k forks source link

Is there a graceful way to drain a keep-alive connection server side? #1652

Open eseres opened 3 months ago

eseres commented 3 months ago

The use case is one of selective connection draining initiated server side. The server must continue to be able to receive new connections, processing new HTTP requests on those connections. We just need to be able to selectively drain a chosen connection without discarding HTTP requests on that connection while doing so. Suspending and subsequently stopping the ranch listener as described here is not a solution for us.

The obvious answer would be to add the Connection: close header to the response of a currently running HTTP 1.1 request. But what is the solution if there is no currently running HTTP 1.1 request and the connection is being kept alive by the client?

A naive solution would be to monitor the HTTP request processes and:

However, this can create race conditions:

Is there a clean and robust way built into Cowboy to handle the above scenarios? Perhaps half closing the connection so that inbound requests are blocked while outgoing responses can still be sent, then letting any current request run to completion and finally closing the connection by sending it the {Close, Socket} message? Or some other way?

Thank you.

essen commented 3 months ago

You must have the pid of the connection process(es) you want to shut down, and call sys:terminate/2 using it. Cowboy will initiate a graceful connection closure. This works for all protocols (Connection: close is HTTP/1.1 only).

If there's no request ongoing, the connection gets closed immediately. Otherwise, the ongoing request(s) will be the last one(s). Note that for HTTP/1.1, pipelined requests that haven't started being processed will not be handled.