Skip to content
Browse files

Make listener supervisor failures less painful

Two general issues were addressed. The first one is the issue with
statically defined pids passed into childspecs. This issue prevents
regular supervisor' children restarts in the case of someone's
failure.

The second one is the not quite appropriate restart strategy.
Changed to rest_for_one which in pair with previous fixes assures
that live connections will not die in the case of partial failure.
Among possible failures are listening socket shutdown or frequent
accept errors.
1 parent 7f4261d commit 8dad1451dd6e41f30741ac7554da238aa63c163a @keynslug keynslug committed
Showing with 47 additions and 30 deletions.
  1. +7 −7 src/ranch_acceptors_sup.erl
  2. +6 −5 src/ranch_conns_sup.erl
  3. +1 −0 src/ranch_listener.erl
  4. +19 −17 src/ranch_listener_sup.erl
  5. +14 −1 src/ranch_server.erl
View
14 src/ranch_acceptors_sup.erl
@@ -17,7 +17,7 @@
-behaviour(supervisor).
%% API.
--export([start_link/7]).
+-export([start_link/5]).
%% supervisor.
-export([init/1]).
@@ -25,16 +25,16 @@
%% API.
-spec start_link(any(), non_neg_integer(), module(), any(),
- module(), pid(), pid()) -> {ok, pid()}.
-start_link(Ref, NbAcceptors, Transport, TransOpts,
- Protocol, ListenerPid, ConnsPid) ->
+ module()) -> {ok, pid()}.
+start_link(Ref, NbAcceptors, Transport, TransOpts, Protocol) ->
supervisor:start_link(?MODULE, [Ref, NbAcceptors, Transport, TransOpts,
- Protocol, ListenerPid, ConnsPid]).
+ Protocol]).
%% supervisor.
-init([Ref, NbAcceptors, Transport, TransOpts,
- Protocol, ListenerPid, ConnsPid]) ->
+init([Ref, NbAcceptors, Transport, TransOpts, Protocol]) ->
+ ListenerPid = ranch_server:lookup_listener(Ref),
+ ConnsPid = ranch_server:lookup_connections_sup(Ref),
LSocket = case proplists:get_value(socket, TransOpts) of
undefined ->
{ok, Socket} = Transport:listen(TransOpts),
View
11 src/ranch_conns_sup.erl
@@ -17,7 +17,7 @@
-behaviour(supervisor).
%% API.
--export([start_link/0]).
+-export([start_link/1]).
-export([start_protocol/5]).
%% supervisor.
@@ -25,9 +25,9 @@
%% API.
--spec start_link() -> {ok, pid()}.
-start_link() ->
- supervisor:start_link(?MODULE, []).
+-spec start_link(any()) -> {ok, pid()}.
+start_link(Ref) ->
+ supervisor:start_link(?MODULE, Ref).
-spec start_protocol(pid(), inet:socket(), module(), module(), any())
-> {ok, pid()}.
@@ -36,6 +36,7 @@ start_protocol(ListenerPid, Socket, Transport, Protocol, Opts) ->
%% supervisor.
-init([]) ->
+init(Ref) ->
+ ok = ranch_server:set_connections_sup(Ref, self()),
{ok, {{simple_one_for_one, 0, 1}, [{?MODULE, {?MODULE, start_protocol, []},
temporary, brutal_kill, worker, [?MODULE]}]}}.
View
1 src/ranch_listener.erl
@@ -101,6 +101,7 @@ set_protocol_options(ServerPid, ProtoOpts) ->
%% @private
init([Ref, MaxConns, ProtoOpts]) ->
+ ok = ranch_server:insert_listener(Ref, self()),
{ok, #state{ref=Ref, max_conns=MaxConns, proto_opts=ProtoOpts}}.
%% @private
View
36 src/ranch_listener_sup.erl
@@ -28,23 +28,25 @@
-> {ok, pid()}.
start_link(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) ->
MaxConns = proplists:get_value(max_connections, TransOpts, 1024),
- {ok, SupPid} = supervisor:start_link(?MODULE, []),
- {ok, ListenerPid} = supervisor:start_child(SupPid,
- {ranch_listener, {ranch_listener, start_link,
- [Ref, MaxConns, ProtoOpts]},
- permanent, 5000, worker, [ranch_listener]}),
- ok = ranch_server:insert_listener(Ref, ListenerPid),
- {ok, ConnsPid} = supervisor:start_child(SupPid,
- {ranch_conns_sup, {ranch_conns_sup, start_link, []},
- permanent, 5000, supervisor, [ranch_conns_sup]}),
- {ok, _PoolPid} = supervisor:start_child(SupPid,
- {ranch_acceptors_sup, {ranch_acceptors_sup, start_link, [
- Ref, NbAcceptors, Transport, TransOpts,
- Protocol, ListenerPid, ConnsPid
- ]}, permanent, 5000, supervisor, [ranch_acceptors_sup]}),
- {ok, SupPid}.
+ supervisor:start_link(?MODULE, {
+ Ref, NbAcceptors, MaxConns, Transport, TransOpts, Protocol, ProtoOpts
+ }).
%% supervisor.
-init([]) ->
- {ok, {{one_for_all, 10, 10}, []}}.
+init({Ref, NbAcceptors, MaxConns, Transport, TransOpts, Protocol, ProtoOpts}) ->
+ ChildSpecs = [
+ %% listener
+ {ranch_listener, {ranch_listener, start_link,
+ [Ref, MaxConns, ProtoOpts]},
+ permanent, 5000, worker, [ranch_listener]},
+ %% conns_sup
+ {ranch_conns_sup, {ranch_conns_sup, start_link, [Ref]},
+ permanent, infinity, supervisor, [ranch_conns_sup]},
+ %% acceptors_sup
+ {ranch_acceptors_sup, {ranch_acceptors_sup, start_link,
+ [Ref, NbAcceptors, Transport, TransOpts, Protocol]
+ }, permanent, infinity, supervisor, [ranch_acceptors_sup]}
+ ],
+ {ok, {{rest_for_one, 10, 10}, ChildSpecs}}.
+
View
15 src/ranch_server.erl
@@ -20,6 +20,8 @@
-export([start_link/0]).
-export([insert_listener/2]).
-export([lookup_listener/1]).
+-export([set_connections_sup/2]).
+-export([lookup_connections_sup/1]).
-export([add_acceptor/2]).
-export([send_to_acceptors/2]).
-export([add_connection/1]).
@@ -52,7 +54,7 @@ start_link() ->
%% @doc Insert a listener into the database.
-spec insert_listener(any(), pid()) -> ok.
insert_listener(Ref, Pid) ->
- true = ets:insert_new(?TAB, {{listener, Ref}, Pid}),
+ true = ets:insert_new(?TAB, {{listener, Ref}, Pid, undefined}),
gen_server:cast(?MODULE, {insert_listener, Ref, Pid}).
%% @doc Lookup a listener in the database.
@@ -60,6 +62,17 @@ insert_listener(Ref, Pid) ->
lookup_listener(Ref) ->
ets:lookup_element(?TAB, {listener, Ref}, 2).
+%% @doc Set a connection supervisor associated with specific listener.
+-spec set_connections_sup(any(), pid()) -> ok.
+set_connections_sup(Ref, Pid) ->
+ true = ets:update_element(?TAB, {listener, Ref}, {3, Pid}),
+ ok.
+
+%% @doc Lookup a connection supervisor used by specific listener.
+-spec lookup_connections_sup(any()) -> pid() | undefined.
+lookup_connections_sup(Ref) ->
+ ets:lookup_element(?TAB, {listener, Ref}, 3).
+
%% @doc Add an acceptor for the given listener.
-spec add_acceptor(any(), pid()) -> ok.
add_acceptor(Ref, Pid) ->

0 comments on commit 8dad145

Please sign in to comment.
Something went wrong with that request. Please try again.