diff options
-rw-r--r-- | guide/listeners.md | 24 | ||||
-rw-r--r-- | src/ranch_conns_sup.erl | 45 |
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. |