0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 20:30:23 +00:00

Add timeout to cowboy_loop

LH: I have added a test that does both hibernate and timeout
    and fixed a related issue. I also tweaked the docs and tests.
This commit is contained in:
jdamanalo 2023-03-09 15:54:41 +08:00 committed by Loïc Hoguin
parent a72bf4105f
commit a81dc8af9d
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764
8 changed files with 165 additions and 25 deletions

View file

@ -17,12 +17,15 @@
-export([upgrade/4]).
-export([upgrade/5]).
-export([loop/4]).
-export([loop/5]).
-export([system_continue/3]).
-export([system_terminate/4]).
-export([system_code_change/4]).
%% From gen_server.
-define(is_timeout(X), ((X) =:= infinity orelse (is_integer(X) andalso (X) >= 0))).
-callback init(Req, any())
-> {ok | module(), Req, any()}
| {module(), Req, any(), any()}
@ -41,40 +44,46 @@
-> {ok, Req, Env} | {suspend, ?MODULE, loop, [any()]}
when Req::cowboy_req:req(), Env::cowboy_middleware:env().
upgrade(Req, Env, Handler, HandlerState) ->
loop(Req, Env, Handler, HandlerState).
loop(Req, Env, Handler, HandlerState, infinity).
-spec upgrade(Req, Env, module(), any(), hibernate)
-spec upgrade(Req, Env, module(), any(), hibernate | timeout())
-> {suspend, ?MODULE, loop, [any()]}
when Req::cowboy_req:req(), Env::cowboy_middleware:env().
upgrade(Req, Env, Handler, HandlerState, hibernate) ->
suspend(Req, Env, Handler, HandlerState).
suspend(Req, Env, Handler, HandlerState);
upgrade(Req, Env, Handler, HandlerState, Timeout) when ?is_timeout(Timeout) ->
loop(Req, Env, Handler, HandlerState, Timeout).
-spec loop(Req, Env, module(), any())
-spec loop(Req, Env, module(), any(), timeout())
-> {ok, Req, Env} | {suspend, ?MODULE, loop, [any()]}
when Req::cowboy_req:req(), Env::cowboy_middleware:env().
%% @todo Handle system messages.
loop(Req=#{pid := Parent}, Env, Handler, HandlerState) ->
loop(Req=#{pid := Parent}, Env, Handler, HandlerState, Timeout) ->
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});
{Req, Env, Handler, HandlerState, Timeout});
%% Calls from supervisor module.
{'$gen_call', From, Call} ->
cowboy_children:handle_supervisor_call(Call, From, [], ?MODULE),
loop(Req, Env, Handler, HandlerState);
loop(Req, Env, Handler, HandlerState, Timeout);
Message ->
call(Req, Env, Handler, HandlerState, Message)
call(Req, Env, Handler, HandlerState, Timeout, Message)
after Timeout ->
call(Req, Env, Handler, HandlerState, Timeout, timeout)
end.
call(Req0, Env, Handler, HandlerState0, Message) ->
call(Req0, Env, Handler, HandlerState0, Timeout, Message) ->
try Handler:info(Message, Req0, HandlerState0) of
{ok, Req, HandlerState} ->
loop(Req, Env, Handler, HandlerState);
loop(Req, Env, Handler, HandlerState, Timeout);
{ok, Req, HandlerState, hibernate} ->
suspend(Req, Env, Handler, HandlerState);
{ok, Req, HandlerState, NewTimeout} when ?is_timeout(NewTimeout) ->
loop(Req, Env, Handler, HandlerState, NewTimeout);
{stop, Req, HandlerState} ->
terminate(Req, Env, Handler, HandlerState, stop)
catch Class:Reason:Stacktrace ->
@ -83,7 +92,7 @@ call(Req0, Env, Handler, HandlerState0, Message) ->
end.
suspend(Req, Env, Handler, HandlerState) ->
{suspend, ?MODULE, loop, [Req, Env, Handler, HandlerState]}.
{suspend, ?MODULE, loop, [Req, Env, Handler, HandlerState, infinity]}.
terminate(Req, Env, Handler, HandlerState, Reason) ->
Result = cowboy_handler:terminate(Reason, Req, HandlerState, Handler),
@ -91,15 +100,15 @@ terminate(Req, Env, Handler, HandlerState, Reason) ->
%% System callbacks.
-spec system_continue(_, _, {Req, Env, module(), any()})
-spec system_continue(_, _, {Req, Env, module(), any(), timeout()})
-> {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).
system_continue(_, _, {Req, Env, Handler, HandlerState, Timeout}) ->
loop(Req, Env, Handler, HandlerState, Timeout).
-spec system_terminate(any(), _, _, {Req, Env, module(), any()})
-spec system_terminate(any(), _, _, {Req, Env, module(), any(), timeout()})
-> {ok, Req, Env} when Req::cowboy_req:req(), Env::cowboy_middleware:env().
system_terminate(Reason, _, _, {Req, Env, Handler, HandlerState}) ->
system_terminate(Reason, _, _, {Req, Env, Handler, HandlerState, _}) ->
terminate(Req, Env, Handler, HandlerState, Reason).
-spec system_code_change(Misc, _, _, _) -> {ok, Misc}