aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--guide/listeners.md24
-rw-r--r--src/ranch_conns_sup.erl45
2 files changed, 49 insertions, 20 deletions
diff --git a/guide/listeners.md b/guide/listeners.md
index 4d01544..d2f7eed 100644
--- a/guide/listeners.md
+++ b/guide/listeners.md
@@ -192,6 +192,30 @@ ranch:set_max_connections(tcp_echo, MaxConns).
The change will occur immediately.
+Using a supervisor for connection processes
+-------------------------------------------
+
+Ranch allows you to define the type of process that will be used
+for the connection processes. By default it expects a `worker`.
+When the `connection_type` configuration value is set to `supervisor`,
+Ranch will consider that the connection process it manages is a
+supervisor and will reflect that in its supervision tree.
+
+Connection processes of type `supervisor` can either handle the
+socket directly or through one of their children. In the latter
+case the start function for the connection process must return
+two pids: the pid of the supervisor you created (that will be
+supervised) and the pid of the protocol handling process (that
+will receive the socket).
+
+Instead of returning `{ok, ConnPid}`, simply return
+`{ok, SupPid, ConnPid}`.
+
+It is very important that the connection process be created
+under the supervisor process so that everything works as intended.
+If not, you will most likely experience issues when the supervised
+process is stopped.
+
Upgrading
---------
diff --git a/src/ranch_conns_sup.erl b/src/ranch_conns_sup.erl
index c2e8a5c..f3a6a0c 100644
--- a/src/ranch_conns_sup.erl
+++ b/src/ranch_conns_sup.erl
@@ -108,30 +108,14 @@ init(Parent, Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol) ->
loop(State=#state{parent=Parent, ref=Ref, conn_type=ConnType,
transport=Transport, protocol=Protocol, opts=Opts,
- ack_timeout=AckTimeout, max_conns=MaxConns},
- CurConns, NbChildren, Sleepers) ->
+ max_conns=MaxConns}, CurConns, NbChildren, Sleepers) ->
receive
{?MODULE, start_protocol, To, Socket} ->
case Protocol:start_link(Ref, Socket, Transport, Opts) of
{ok, Pid} ->
- case Transport:controlling_process(Socket, Pid) of
- ok ->
- Pid ! {shoot, Ref, Transport, Socket, AckTimeout},
- put(Pid, true),
- CurConns2 = CurConns + 1,
- if CurConns2 < MaxConns ->
- To ! self(),
- loop(State, CurConns2, NbChildren + 1,
- Sleepers);
- true ->
- loop(State, CurConns2, NbChildren + 1,
- [To|Sleepers])
- end;
- {error, _} ->
- Transport:close(Socket),
- exit(Pid, kill),
- loop(State, CurConns, NbChildren, Sleepers)
- end;
+ shoot(State, CurConns, NbChildren, Sleepers, To, Socket, Pid, Pid);
+ {ok, SupPid, ProtocolPid} when ConnType =:= supervisor ->
+ shoot(State, CurConns, NbChildren, Sleepers, To, Socket, SupPid, ProtocolPid);
Ret ->
To ! self(),
error_logger:error_msg(
@@ -200,6 +184,27 @@ loop(State=#state{parent=Parent, ref=Ref, conn_type=ConnType,
[Ref, Msg])
end.
+shoot(State=#state{ref=Ref, transport=Transport, ack_timeout=AckTimeout, max_conns=MaxConns},
+ CurConns, NbChildren, Sleepers, To, Socket, SupPid, ProtocolPid) ->
+ case Transport:controlling_process(Socket, ProtocolPid) of
+ ok ->
+ ProtocolPid ! {shoot, Ref, Transport, Socket, AckTimeout},
+ put(SupPid, true),
+ CurConns2 = CurConns + 1,
+ if CurConns2 < MaxConns ->
+ To ! self(),
+ loop(State, CurConns2, NbChildren + 1, Sleepers);
+ true ->
+ loop(State, CurConns2, NbChildren + 1, [To|Sleepers])
+ end;
+ {error, _} ->
+ Transport:close(Socket),
+ %% Only kill the supervised pid, because the connection's pid,
+ %% when different, is supposed to be sitting under it and linked.
+ exit(SupPid, kill),
+ loop(State, CurConns, NbChildren, Sleepers)
+ end.
+
-spec terminate(#state{}, any(), non_neg_integer()) -> no_return().
%% Kill all children and then exit. We unlink first to avoid
%% getting a message for each child getting killed.