aboutsummaryrefslogtreecommitdiffstats
path: root/doc/src
diff options
context:
space:
mode:
Diffstat (limited to 'doc/src')
-rw-r--r--doc/src/guide/book.asciidoc2
-rw-r--r--doc/src/guide/connection_draining.asciidoc69
2 files changed, 71 insertions, 0 deletions
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).
+----