Browse Source

Ensure listener restart with changed TransOpts

j.uhlig 7 years ago
parent
commit
963f53942f
5 changed files with 63 additions and 21 deletions
  1. 13 11
      src/ranch_conns_sup.erl
  2. 3 6
      src/ranch_listener_sup.erl
  3. 4 4
      src/ranch_server.erl
  4. 38 0
      test/acceptor_SUITE.erl
  5. 5 0
      test/ranch_ct_hook.erl

+ 13 - 11
src/ranch_conns_sup.erl

@@ -18,12 +18,12 @@
 -module(ranch_conns_sup).
 
 %% API.
--export([start_link/6]).
+-export([start_link/3]).
 -export([start_protocol/2]).
 -export([active_connections/1]).
 
 %% Supervisor internals.
--export([init/7]).
+-export([init/4]).
 -export([system_continue/3]).
 -export([system_terminate/4]).
 -export([system_code_change/4]).
@@ -45,11 +45,10 @@
 
 %% API.
 
--spec start_link(ranch:ref(), conn_type(), shutdown(), module(),
-	timeout(), module()) -> {ok, pid()}.
-start_link(Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol) ->
+-spec start_link(ranch:ref(), module(), module()) -> {ok, pid()}.
+start_link(Ref, Transport, Protocol) ->
 	proc_lib:start_link(?MODULE, init,
-		[self(), Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol]).
+		[self(), Ref, Transport, Protocol]).
 
 %% We can safely assume we are on the same node as the supervisor.
 %%
@@ -94,17 +93,20 @@ active_connections(SupPid) ->
 
 %% Supervisor internals.
 
--spec init(pid(), ranch:ref(), conn_type(), shutdown(),
-	module(), timeout(), module()) -> no_return().
-init(Parent, Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol) ->
+-spec init(pid(), ranch:ref(), module(), module()) -> no_return().
+init(Parent, Ref, Transport, Protocol) ->
 	process_flag(trap_exit, true),
 	ok = ranch_server:set_connections_sup(Ref, self()),
 	MaxConns = ranch_server:get_max_connections(Ref),
-	Opts = ranch_server:get_protocol_options(Ref),
+	TransOpts = ranch_server:get_transport_options(Ref),
+	ConnType = proplists:get_value(connection_type, TransOpts, worker),
+	Shutdown = proplists:get_value(shutdown, TransOpts, 5000),
+	AckTimeout = proplists:get_value(ack_timeout, TransOpts, 5000),
+	ProtoOpts = ranch_server:get_protocol_options(Ref),
 	ok = proc_lib:init_ack(Parent, {ok, self()}),
 	loop(#state{parent=Parent, ref=Ref, conn_type=ConnType,
 		shutdown=Shutdown, transport=Transport, protocol=Protocol,
-		opts=Opts, ack_timeout=AckTimeout, max_conns=MaxConns}, 0, 0, []).
+		opts=ProtoOpts, ack_timeout=AckTimeout, max_conns=MaxConns}, 0, 0, []).
 
 loop(State=#state{parent=Parent, ref=Ref, conn_type=ConnType,
 		transport=Transport, protocol=Protocol, opts=Opts,

+ 3 - 6
src/ranch_listener_sup.erl

@@ -25,17 +25,14 @@ start_link(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts) ->
 	ranch_server:set_new_listener_opts(Ref, MaxConns, TransOpts, ProtoOpts,
 		[Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts]),
 	supervisor:start_link(?MODULE, {
-		Ref, NumAcceptors, Transport, TransOpts, Protocol
+		Ref, NumAcceptors, Transport, Protocol
 	}).
 
-init({Ref, NumAcceptors, Transport, TransOpts, Protocol}) ->
+init({Ref, NumAcceptors, Transport, Protocol}) ->
 	ok = ranch_server:set_listener_sup(Ref, self()),
-	AckTimeout = proplists:get_value(ack_timeout, TransOpts, 5000),
-	ConnType = proplists:get_value(connection_type, TransOpts, worker),
-	Shutdown = proplists:get_value(shutdown, TransOpts, 5000),
 	ChildSpecs = [
 		{ranch_conns_sup, {ranch_conns_sup, start_link,
-				[Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol]},
+				[Ref, Transport, Protocol]},
 			permanent, infinity, supervisor, [ranch_conns_sup]},
 		{ranch_acceptors_sup, {ranch_acceptors_sup, start_link,
 				[Ref, NumAcceptors, Transport]},

+ 4 - 4
src/ranch_server.erl

@@ -156,10 +156,10 @@ init([]) ->
 	{ok, #state{monitors=ConnMonitors++ListenerMonitors}}.
 
 handle_call({set_new_listener_opts, Ref, MaxConns, TransOpts, ProtoOpts, StartArgs}, _, State) ->
-	ets:insert(?TAB, {{max_conns, Ref}, MaxConns}),
-	ets:insert(?TAB, {{trans_opts, Ref}, TransOpts}),
-	ets:insert(?TAB, {{proto_opts, Ref}, ProtoOpts}),
-	ets:insert(?TAB, {{listener_start_args, Ref}, StartArgs}),
+	ets:insert_new(?TAB, {{max_conns, Ref}, MaxConns}),
+	ets:insert_new(?TAB, {{trans_opts, Ref}, TransOpts}),
+	ets:insert_new(?TAB, {{proto_opts, Ref}, ProtoOpts}),
+	ets:insert_new(?TAB, {{listener_start_args, Ref}, StartArgs}),
 	{reply, ok, State};
 handle_call({set_connections_sup, Ref, Pid}, _,
 		State=#state{monitors=Monitors}) ->

+ 38 - 0
test/acceptor_SUITE.erl

@@ -62,6 +62,7 @@ groups() ->
 	]}, {supervisor, [
 		connection_type_supervisor,
 		connection_type_supervisor_separate_from_connection,
+		supervisor_changed_options_restart,
 		supervisor_clean_child_restart,
 		supervisor_clean_conns_sup_restart,
 		supervisor_clean_restart,
@@ -799,6 +800,36 @@ connection_type_supervisor_separate_from_connection(_) ->
 	{'EXIT', _} = begin catch ranch:get_port(Name) end,
 	ok.
 
+supervisor_changed_options_restart(_) ->
+	doc("Ensure that a listener is restarted with changed transport options."),
+	Name = name(),
+	%% Start a listener using send_timeout as option change marker.
+	{ok, ListenerSupPid1} = ranch:start_listener(Name,
+		ranch_tcp, [{send_timeout, 300000}],
+		echo_protocol, []),
+	%% Ensure send_timeout is really set to initial value.
+	{ok, [{send_timeout, 300000}]}
+		= inet:getopts(do_get_listener_socket(ListenerSupPid1), [send_timeout]),
+	%% Change send_timeout option.
+	ok = ranch:suspend_listener(Name),
+	ok = ranch:set_transport_options(Name, [{send_timeout, 300001}]),
+	ok = ranch:resume_listener(Name),
+	%% Ensure send_timeout is really set to the changed value.
+	{ok, [{send_timeout, 300001}]}
+		= inet:getopts(do_get_listener_socket(ListenerSupPid1), [send_timeout]),
+	%% Crash the listener_sup process, allow a short time for restart to succeed.
+	exit(ListenerSupPid1, kill),
+	timer:sleep(1000),
+	%% Obtain pid of restarted listener_sup process.
+	[ListenerSupPid2] = [Pid || {{ranch_listener_sup, Ref}, Pid, supervisor, _}
+		<- supervisor:which_children(ranch_sup), Ref =:= Name],
+	%% Ensure send_timeout is still set to the changed value.
+	{ok, [{send_timeout, 300001}]}
+		= inet:getopts(do_get_listener_socket(ListenerSupPid2), [send_timeout]),
+	ok = ranch:stop_listener(Name),
+	{'EXIT', _} = begin catch ranch:get_port(Name) end,
+	ok.
+
 supervisor_clean_child_restart(Config) ->
 	case code:is_module_native(?MODULE) of
 		true -> doc("This test uses tracing and is not compatible with native code.");
@@ -1034,3 +1065,10 @@ clean_traces() ->
 	after 0 ->
 		ok
 	end.
+
+do_get_listener_socket(ListenerSupPid) ->
+	[AcceptorsSupPid] = [Pid || {ranch_acceptors_sup, Pid, supervisor, _}
+		<- supervisor:which_children(ListenerSupPid)],
+	{links, Links} = erlang:process_info(AcceptorsSupPid, links),
+	[LSocket] = [P || P <- Links, is_port(P)],
+	LSocket.

+ 5 - 0
test/ranch_ct_hook.erl

@@ -17,6 +17,11 @@
 -export([init/2]).
 
 init(_, _) ->
+	%% Allow a more relaxed restart intensity because
+	%% some tests will cause quick restarts of several
+	%% ranch_sup children.
+	application:set_env(ranch, ranch_sup_intensity, 10),
+	application:set_env(ranch, ranch_sup_period, 1),
 	ct_helper:start([ranch]),
 	ct_helper:make_certs_in_ets(),
 	error_logger:add_report_handler(ct_helper_error_h),