From c7485760d3868219ea2406f225c0c21d6b753ec0 Mon Sep 17 00:00:00 2001 From: juhlig Date: Fri, 5 Jul 2019 15:42:22 +0200 Subject: Document connection draining --- doc/src/guide/book.asciidoc | 2 + doc/src/guide/connection_draining.asciidoc | 69 ++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 doc/src/guide/connection_draining.asciidoc diff --git a/doc/src/guide/book.asciidoc b/doc/src/guide/book.asciidoc index d4080b3..e87e7b3 100644 --- a/doc/src/guide/book.asciidoc +++ b/doc/src/guide/book.asciidoc @@ -21,6 +21,8 @@ include::parsers.asciidoc[Writing parsers] include::ssl_auth.asciidoc[SSL client authentication] +include::connection_draining.asciidoc[Connection draining] + = Advanced include::internals.asciidoc[Internals] diff --git a/doc/src/guide/connection_draining.asciidoc b/doc/src/guide/connection_draining.asciidoc new file mode 100644 index 0000000..cee4dfa --- /dev/null +++ b/doc/src/guide/connection_draining.asciidoc @@ -0,0 +1,69 @@ +== Connection draining + +Stopping a Ranch listener via `ranch:stop_listener/1` will invariably kill +all connection processes the listener hosts. However, you may want to stop +a listener in a graceful fashion, ie by not accepting any new connections, +but allowing the existing connection processes to exit by themselves instead +of being killed. + +For this purpose, you should first suspend the listeners you wish to +stop gracefully, and then wait for its connection count to drop to +zero. + +.Draining a single listener + +[source,erlang] +---- +ok = ranch:suspend_listener(Ref), +ok = ranch:wait_for_connections(Ref, '==', 0), +ok = ranch:stop_listener(Ref). +---- + +If you want to drain more than just one listener, it may be important to first suspend +them all before beginning to wait for their connection counts to reach zero. Otherwise, +the not yet suspended listeners will still be accepting connections while you wait for +the suspended ones to be drained. + +.Draining multiple listeners + +[source,erlang] +---- +lists:foreach( + fun (Ref) -> + ok = ranch:suspend_listener(Ref) + end, + Refs +), +lists:foreach( + fun (Ref) -> + ok = ranch:wait_for_connections(Ref, '==', 0), + ok = ranch:stop_listener(Ref) + end, + Refs +). +---- + +If you have long-running connection processes hosted by the listener you want to stop +gracefully, draining may take a long time, possibly forever. If you just want to give +the connection processes a chance to finish, but are not willing to wait for infinity, +the waiting part could be handled in a separate process. + +.Draining a listener with a timeout + +[source,erlang] +---- +ok = ranch:suspend_listener(Ref), +{DrainPid, DrainRef} = spawn_monitor( + fun () -> + ok = ranch:wait_for_connections(Ref, '==', 0) + end +), +receive + {'DOWN', DrainRef, process, DrainPid, _} -> + ok +after DrainTimeout -> + exit(DrainPid, kill), + ok +end, +ok = ranch:stop_listener(Ref). +---- -- cgit v1.2.3