Просмотр исходного кода

Add initial support for system messages in cowboy_loop

Loïc Hoguin 7 лет назад
Родитель
Сommit
4d5174632c
3 измененных файлов с 38 добавлено и 7 удалено
  1. 33 1
      src/cowboy_loop.erl
  2. 2 2
      test/handlers/long_polling_sys_h.erl
  3. 3 4
      test/sys_SUITE.erl

+ 33 - 1
src/cowboy_loop.erl

@@ -19,6 +19,10 @@
 -export([upgrade/5]).
 -export([loop/4]).
 
+-export([system_continue/3]).
+-export([system_terminate/4]).
+-export([system_code_change/4]).
+
 -callback init(Req, any())
 	-> {ok | module(), Req, any()}
 	| {module(), Req, any(), any()}
@@ -49,8 +53,18 @@ upgrade(Req, Env, Handler, HandlerState, hibernate) ->
 	-> {ok, Req, Env} | {suspend, ?MODULE, loop, [any()]}
 	when Req::cowboy_req:req(), Env::cowboy_middleware:env().
 %% @todo Handle system messages.
-loop(Req, Env, Handler, HandlerState) ->
+loop(Req=#{pid := Parent}, Env, Handler, HandlerState) ->
 	receive
+		%% System messages.
+		{'EXIT', Parent, Reason} ->
+			terminate(Req, Env, Handler, HandlerState, Reason);
+		{system, From, Request} ->
+			sys:handle_system_msg(Request, From, Parent, ?MODULE, [],
+				{Req, Env, Handler, HandlerState});
+		%% Calls from supervisor module.
+		{'$gen_call', From, Call} ->
+			cowboy_children:handle_supervisor_call(Call, From, [], ?MODULE),
+			loop(Req, Env, Handler, HandlerState);
 		Message ->
 			call(Req, Env, Handler, HandlerState, Message)
 	end.
@@ -74,3 +88,21 @@ suspend(Req, Env, Handler, HandlerState) ->
 terminate(Req, Env, Handler, HandlerState, Reason) ->
 	Result = cowboy_handler:terminate(Reason, Req, HandlerState, Handler),
 	{ok, Req, Env#{result => Result}}.
+
+%% System callbacks.
+
+-spec system_continue(_, _, {Req, Env, module(), any()})
+	-> {ok, Req, Env} | {suspend, ?MODULE, loop, [any()]}
+	when Req::cowboy_req:req(), Env::cowboy_middleware:env().
+system_continue(_, _, {Req, Env, Handler, HandlerState}) ->
+	loop(Req, Env, Handler, HandlerState).
+
+-spec system_terminate(any(), _, _, {Req, Env, module(), any()})
+	-> {ok, Req, Env} when Req::cowboy_req:req(), Env::cowboy_middleware:env().
+system_terminate(Reason, _, _, {Req, Env, Handler, HandlerState}) ->
+	terminate(Req, Env, Handler, HandlerState, Reason).
+
+-spec system_code_change(Misc, _, _, _) -> {ok, Misc}
+	when Misc::{cowboy_req:req(), cowboy_middleware:env(), module(), any()}.
+system_code_change(Misc, _, _, _) ->
+	{ok, Misc}.

+ 2 - 2
test/handlers/long_polling_sys_h.erl

@@ -10,7 +10,7 @@
 init(Req, _) ->
 	process_flag(trap_exit, true),
 	erlang:send_after(500, self(), timeout),
-	{cowboy_loop, Req, undefined, hibernate}.
+	{cowboy_loop, Req, undefined}.
 
 info(timeout, Req, State) ->
 	%% Send an unused status code to make sure there's no
@@ -19,5 +19,5 @@ info(timeout, Req, State) ->
 info(_, Req, State) ->
 	{ok, Req, State}.
 
-terminate({crash, _, _}, _, _) ->
+terminate(_, _, _) ->
 	ok.

+ 3 - 4
test/sys_SUITE.erl

@@ -400,9 +400,8 @@ trap_exit_parent_exit_loop(Config) ->
 	Parent = do_get_remote_pid_tcp(Socket),
 	[{_, Pid, _, _}] = supervisor:which_children(Parent),
 	Pid ! {'EXIT', Parent, shutdown},
-	%% We're getting a 500 because the process exited in an unexpected way
-	%% from Cowboy's point of view.
-	{ok, "HTTP/1.1 500 "} = gen_tcp:recv(Socket, 13, 1000),
+	%% We exit normally but didn't send a response.
+	{ok, "HTTP/1.1 204 "} = gen_tcp:recv(Socket, 13, 1000),
 	false = is_process_alive(Pid),
 	ok.
 
@@ -483,7 +482,7 @@ trap_exit_other_exit_loop(Config) ->
 	timer:sleep(100),
 	Parent = do_get_remote_pid_tcp(Socket),
 	[{_, Pid, _, _}] = supervisor:which_children(Parent),
-	Pid ! {'EXIT', Parent, shutdown},
+	Pid ! {'EXIT', self(), shutdown},
 	%% The process stays alive.
 	{ok, "HTTP/1.1 299 "} = gen_tcp:recv(Socket, 13, 1000),
 	true = is_process_alive(Pid),