[erlang-questions] uncatched cowboy websocket handler termination

pablo platt pablo.platt@REDACTED
Sun May 12 17:08:48 CEST 2013


I don't know enough in websocket_init/3 to create the session. I need the
userid and auth token which are sent with the first websocket packet.

If the session is linked to the websocket pid, Is it possible that
websocket_terminate/3 will be called but the session won't get an exit
message?

>From my code, I thought that the only options are:
- The websocket pid is dead when trying to link to it so the session will
crash.
- A link is created. If the websocket pid dies, the session will get an
exit message.


Is there a race condition in my implementation?


On Sun, May 12, 2013 at 6:01 PM, fxmy wang <fxmywc@REDACTED> wrote:

> hi pablo,
>     When a websocket connection shuts down, the function *ws_handler:websocket_terminate(_Reason,
> _Req, _State) *will be called.
>     So you probably should handle you session-ending through this function
> call
>
>     And more generally, it's a good way to initialize your session through
> *websocket_init(_TransportName, Req, _Opts) *and do the clean up work in
> *ws_handler:websocket_terminate(_Reason, _Req, _State) *
>
> On Tuesday, May 7, 2013 2:28:51 AM UTC+8, pablo platt wrote:
>>
>> Hi,
>>
>> I'm using a cowboy websocket handler as a simple chat transport.
>> The websocket handler pass messages to a session gen_server.
>> The session gen_server traps exits and links to the websocket pid
>> so if the websocket pid dies, the session gen_server should terminate as
>> well.
>>
>> I sometimes see sessions that thinks that the websocket pid is still
>> alive although checking with is_process_alive/1 shows it is not. That leads
>> to zombie sessions that accumulate over time.
>>
>> Is there a race condition in my code or something else I'm missing in
>> catching the termination of the websocket pid?
>>
>> Please see a simplified version of the websocket handler and the session
>> gen_server below.
>>
>> Thanks
>>
>> -module(my_session).
>> -behaviour(gen_server).
>>
>> -export([handle_message/2]).
>> -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
>> terminate/2, code_change/3]).
>>
>> -record(state, {ws}).
>>
>> handle_message(undefined, Msg) ->
>>     case supervisor:start_child(my_session_sup, [Msg, self()]) of
>>         {error, Reason} -> {close, 1000, <<"">>};
>>         {ok, Pid} ->
>>             gen_server:call(Pid, {websocket, self()}),
>>             self() ! {session, Pid},
>>             {text, <<"ok">>}
>>     end;
>> handle_message(Pid, Msg) ->
>>     gen_server:call(Pid, {msg, Msg}).
>>
>> init([Msg, WS]) ->
>>     case auth(Msg) of
>>         false -> {stop, normal};
>>         true ->
>>             process_flag(trap_exit,true),
>>             {ok, #state{})
>>     end.
>>
>> handle_call({websocket, Pid}, _, State) ->
>>   link(Pid),
>>   {reply, ok, State#state{ws=Pid}};
>> handle_call({msg, Msg}, _, State) ->
>>     Resp = msg(Msg, State),
>>    {reply, Resp, State}.
>>
>> handle_info({'EXIT', _Pid, _Reason}, State) ->
>>     {stop, normal, State}.
>>
>> ...
>>
>>
>> -module(ws_handler).
>> -behaviour(cowboy_websocket_handler).
>>
>> -export([init/3]).
>> -export([websocket_init/3]).
>> -export([websocket_handle/3]).
>> -export([websocket_info/3]).
>> -export([websocket_terminate/3]).
>>
>> -record(state, {tref, session}).
>>
>> init({tcp, http}, _Req, _Opts) ->
>>     {upgrade, protocol, cowboy_websocket}.
>>
>> websocket_init(_TransportName, Req, _Opts) ->
>>     Tref = erlang:send_after(10000, self(), timeout),
>>     {ok, Req, #state{tref=Tref}}.
>>
>> websocket_handle({text, ""}, Req, State) ->
>>     erlang:cancel_timer(State#state.tref),
>>     Tref = erlang:send_after(10000, self(), timeout),
>>     {ok, Req, State#state{tref=Tref}};
>> websocket_handle({text, Msg}, Req, State) ->
>>     Tref = erlang:send_after(10000, self(), timeout),
>>     Resp = my_session:handle_message(State#state.session, Msg),
>>     {reply, Resp, Req, State#state{tref=Tref}};
>> websocket_handle(_Data, Req, State) ->
>>     {ok, Req, State}.
>>
>> websocket_info({session, Pid}, Req, State) ->
>>     {ok, Req, State#state{session=Pid}};
>> websocket_info({terminate}, Req, State) ->
>>     {reply, {close, 1000, <<"">>}, Req, State};
>> websocket_info({timeout, _Ref, Msg}, Req, State) ->
>>     {shutdown, Req, State};
>> websocket_info(_Info, Req, State) ->
>>     {ok, Req, State}.
>>
>> websocket_terminate(_Reason, _Req, _State) ->
>>     ok.
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130512/cd0fa821/attachment.htm>


More information about the erlang-questions mailing list