<div dir="ltr"><div><div><div>In my tests the session thinks that the websocket pid is alive although it is not.<br></div>How come it didn't get the exit message?<br><br></div>I'll use websocket_terminate/3 as a last resort but I want to understand why I'm not getting the exit message first.<br>
</div>Is it possible that cowboy somehow prevent sending this message?<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, May 12, 2013 at 6:42 PM, fxmy wang <span dir="ltr"><<a href="mailto:fxmywc@gmail.com" target="_blank">fxmywc@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im"><div>>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.<br>
</div></div><div>The <strong>Req</strong> in <strong>init({tcp, http}, Req, Opts)</strong> and<strong> websocket_init(_TransportName, Req, _Opts) </strong>contains a lot of things including User-Agents , Cookies, RequestedUrls etc..</div>
<div>You might find things you need there.</div><div>And if unlucky, you can just let the browser to send informations explicitely after websocket connection is set up , then handled in <strong>websocket_handle({text, Msg}, Req, State)</strong></div>
<div class="im"><div><strong><br></strong></div><div>>
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?
<strong><br></strong></div></div><div>Once the websocket connection shuts down , <strong>websocket_terminate/3</strong> will be called , according to <a href="http://ninenines.eu/docs/en/cowboy/HEAD/guide/ws_handlers" target="_blank">here</a>.</div>
<div>And maybe cowboy just keeps this pid alive after called <strong>websocket_terminate/3</strong> for some other use. I can`t really be sure cause I`m kind of lost in cowboy`s source code :( . This is one possibility that your linked session process does not get a EXIT message.</div>
<div><br></div><div>And , have you considering add a call in <strong>websocket_terminate/3</strong> like <strong>my_session:kill_session( self(), ...) </strong> to explicitly end your session?</div><div class="im"><br>On Sunday, May 12, 2013 11:08:48 PM UTC+8, pablo platt wrote:</div>
<blockquote class="gmail_quote" style="margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im"><div dir="ltr"><div><div><div>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.<br>
</div><br></div>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?<br>
<br></div><div><div>From my code, I thought that the only options are:<br></div><div>- The websocket pid is dead when trying to link to it so the session will crash.<br></div><div>- A link is created. If the websocket pid dies, the session will get an exit message.<br>
<br><br></div><div>Is there a race condition in my implementation?<br></div></div></div></div><div><div class="h5"><div><br><br><div class="gmail_quote">On Sun, May 12, 2013 at 6:01 PM, fxmy wang <span dir="ltr"><<a>fxm...@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>hi pablo,<br></div><div> When a websocket connection shuts down, the function <b>ws_handler:websocket_terminate(_Reason, _Req, _State) </b>will be called.</div>
<div> So you probably should handle you session-ending through this function call</div><div><br></div><div> And more generally, it's a good way to initialize your session through <b>websocket_init(_TransportName, Req, _Opts) </b>and do the clean up work in
<b>ws_handler:websocket_terminate(_Reason, _Req, _State) </b>
</div><div><div><br>On Tuesday, May 7, 2013 2:28:51 AM UTC+8, pablo platt wrote:<blockquote class="gmail_quote" style="margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">
<div><div><div><div><div><div><div><div>Hi,<br><br></div>I'm using a cowboy websocket handler as a simple chat transport.<br></div>The websocket handler pass messages to a session gen_server.<br></div><div>
The session gen_server traps exits and links to the websocket pid <br></div>so if the websocket pid dies, the session gen_server should terminate as well.<br><br></div></div>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.<br>
<br></div>Is there a race condition in my code or something else I'm missing in catching the termination of the websocket pid?<br><br></div>Please see a simplified version of the websocket handler and the session gen_server below.<br>
<br></div><div>Thanks<br></div><div><br>-module(my_session).<br>-behaviour(gen_server).<br><br>-export([handle_message/2]).<br>-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).<br>
<br>-record(state, {ws}).<br><br>handle_message(undefined, Msg) -><br> case supervisor:start_child(my_session_sup, [Msg, self()]) of<br> {error, Reason} -> {close, 1000, <<"">>};<br>
{ok, Pid} -><br>
</div><div> gen_server:call(Pid, {websocket, self()}),<br></div><div> self() ! {session, Pid},<br> {text, <<"ok">>}<br> end;<br>handle_message(Pid, Msg) -><br>
gen_server:call(Pid, {msg, Msg}).<br>
<br>init([Msg, WS]) -><br> case auth(Msg) of<br> false -> {stop, normal};<br> true -><br> process_flag(trap_exit,true),<br> {ok, #state{})<br> end.<br><br>handle_call({websocket, Pid}, _, State) -><br>
</div><div> link(Pid),<br></div> {reply, ok, State#state{ws=Pid}};<br><div>handle_call({msg, Msg}, _, State) -><br> Resp = msg(Msg, State),<br> {reply, Resp, State}.<br><br>handle_info({'EXIT', _Pid, _Reason}, State) -><br>
{stop, normal, State}.<br><br>...<br><br><br>-module(ws_handler).<br>-behaviour(cowboy_websocket_handler).<br><br>-export([init/3]).<br>-export([websocket_init/3]).<br>-export([websocket_handle/3]).<br>-export([websocket_info/3]).<br>
-export([websocket_terminate/3]).<br><br>-record(state, {tref, session}).<br><br>init({tcp, http}, _Req, _Opts) -><br> {upgrade, protocol, cowboy_websocket}.<br><br>websocket_init(_TransportName, Req, _Opts) -><br>
Tref = erlang:send_after(10000, self(), timeout),<br> {ok, Req, #state{tref=Tref}}.<br><br>websocket_handle({text, ""}, Req, State) -><br> erlang:cancel_timer(State#state.tref),<br> Tref = erlang:send_after(10000, self(), timeout),<br>
{ok, Req, State#state{tref=Tref}}; <br>websocket_handle({text, Msg}, Req, State) -><br> Tref = erlang:send_after(10000, self(), timeout),<br> Resp = my_session:handle_message(State#state.session, Msg),<br>
{reply, Resp, Req, State#state{tref=Tref}};<br>websocket_handle(_Data, Req, State) -><br> {ok, Req, State}.<br><br>websocket_info({session, Pid}, Req, State) -><br> {ok, Req, State#state{session=Pid}};<br>
websocket_info({terminate}, Req, State) -><br> {reply, {close, 1000, <<"">>}, Req, State}; <br>websocket_info({timeout, _Ref, Msg}, Req, State) -><br> {shutdown, Req, State};<br>websocket_info(_Info, Req, State) -><br>
{ok, Req, State}.<br><br>websocket_terminate(_Reason, _Req, _State) -><br> ok.<br></div></div>
</blockquote></div></div></blockquote></div><br></div>
</div></div></blockquote></blockquote></div><br></div>