Browse Source

Ensure ranch_conns_sup doesn't crash on protocol start crash

Loïc Hoguin 9 years ago
parent
commit
ee1f827828
3 changed files with 27 additions and 1 deletions
  1. 8 1
      src/ranch_conns_sup.erl
  2. 12 0
      test/acceptor_SUITE.erl
  3. 7 0
      test/crash_protocol.erl

+ 8 - 1
src/ranch_conns_sup.erl

@@ -111,7 +111,7 @@ loop(State=#state{parent=Parent, ref=Ref, conn_type=ConnType,
 		max_conns=MaxConns}, CurConns, NbChildren, Sleepers) ->
 	receive
 		{?MODULE, start_protocol, To, Socket} ->
-			case Protocol:start_link(Ref, Socket, Transport, Opts) of
+			try Protocol:start_link(Ref, Socket, Transport, Opts) of
 				{ok, Pid} ->
 					shoot(State, CurConns, NbChildren, Sleepers, To, Socket, Pid, Pid);
 				{ok, SupPid, ProtocolPid} when ConnType =:= supervisor ->
@@ -124,6 +124,13 @@ loop(State=#state{parent=Parent, ref=Ref, conn_type=ConnType,
 						[Ref, Protocol, Ret]),
 					Transport:close(Socket),
 					loop(State, CurConns, NbChildren, Sleepers)
+			catch Class:Reason ->
+				To ! self(),
+				error_logger:error_msg(
+					"Ranch listener ~p connection process start failure; "
+					"~p:start_link/4 crashed with reason: ~p:~999999p~n",
+					[Ref, Protocol, Class, Reason]),
+				loop(State, CurConns, NbChildren, Sleepers)
 			end;
 		{?MODULE, active_connections, To, Tag} ->
 			To ! {Tag, CurConns},

+ 12 - 0
test/acceptor_SUITE.erl

@@ -48,6 +48,7 @@ groups() ->
 		supervisor_clean_conns_sup_restart,
 		supervisor_clean_restart,
 		supervisor_conns_alive,
+		supervisor_protocol_start_link_crash,
 		supervisor_server_recover_state
 	]}].
 
@@ -459,6 +460,17 @@ supervisor_conns_alive(_) ->
 	ok = clean_traces(),
 	ok = ranch:stop_listener(Name).
 
+supervisor_protocol_start_link_crash(_) ->
+	doc("Ensure a protocol start crash does not kill all connections."),
+	Name = supervisor_protocol_start_link_crash,
+	{ok, _} = ranch:start_listener(Name, 1, ranch_tcp, [], crash_protocol, []),
+	ConnsSup = ranch_server:get_connections_sup(Name),
+	Port = ranch:get_port(Name),
+	{ok, _} = gen_tcp:connect("localhost", Port, [binary, {active, true}, {packet, raw}]),
+	receive after 500 -> ok end,
+	ConnsSup = ranch_server:get_connections_sup(Name),
+	ok = ranch:stop_listener(Name).
+
 supervisor_server_recover_state(_) ->
 	%% Verify that if ranch_server crashes it regains its state and monitors
 	%% ranch_conns_sup that were previously registered.

+ 7 - 0
test/crash_protocol.erl

@@ -0,0 +1,7 @@
+-module(crash_protocol).
+
+-export([start_link/4]).
+
+-spec start_link(_, _, _, _) -> no_return().
+start_link(_, _, _, _) ->
+	exit(crash).