From c7485760d3868219ea2406f225c0c21d6b753ec0 Mon Sep 17 00:00:00 2001
From: juhlig <j.uhlig@mailingwork.de>
Date: Fri, 5 Jul 2019 15:42:22 +0200
Subject: Document connection draining

---
 doc/src/guide/connection_draining.asciidoc | 69 ++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 doc/src/guide/connection_draining.asciidoc

(limited to 'doc/src/guide/connection_draining.asciidoc')

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

