From: Michal D. <mic...@gm...> - 2010-12-21 17:07:15
|
Hi, I'm trying to write a fairly simple AJAX multiplayer game in Yaws. I spawn a seperate process to handle the server state across all clients. There are two .yaws files, both called from JavaScript by xml http request objects via GET. submit.yaws - query string holds a an action performed by the player (affects state server, client ignores any response). request.yaws - subscribes to state server modification notifications, then wais for a message from the state server with the new state. The problem is that once submit.yaws is accessed a process dies (different pid from processes handling submit.yaws or request.yaws). After this, the request.yaws seems to hang and no new updates come in. The process that dies shows up with the following message: =ERROR REPORT==== 21-Dec-2010::12:03:56 === Yaws process died: {function_clause,[{yaws_server,binary_size,[0,<0.71.0>]}, {yaws_server,binary_size,2}, {yaws_server,deliver_accumulated,5}, {yaws_server,finish_up_dyn_file,2}, {yaws_server,aloop,3}, {yaws_server,acceptor0,2}, {proc_lib,init_p_do_apply,3}]} Any hints on what's going on? Please contact me if something is not clear. Cheers, Michal |
From: Steve V. <vi...@ie...> - 2010-12-21 21:51:27
|
On Tue, Dec 21, 2010 at 12:07 PM, Michal D. <mic...@gm...> wrote: > Hi, > > I'm trying to write a fairly simple AJAX multiplayer game in Yaws. I spawn > a seperate process to handle the server state across all clients. There are > two .yaws files, both called from JavaScript by xml http request objects via > GET. > > submit.yaws - query string holds a an action performed by the player > (affects state server, client ignores any response). > request.yaws - subscribes to state server modification notifications, then > wais for a message from the state server with the new state. > > The problem is that once submit.yaws is accessed a process dies (different > pid from processes handling submit.yaws or request.yaws). After this, the > request.yaws seems to hang and no new updates come in. The process that dies > shows up with the following message: > > =ERROR REPORT==== 21-Dec-2010::12:03:56 === > Yaws process died: {function_clause,[{yaws_server,binary_size,[0,<0.71.0>]}, > {yaws_server,binary_size,2}, > {yaws_server,deliver_accumulated,5}, > {yaws_server,finish_up_dyn_file,2}, > {yaws_server,aloop,3}, > {yaws_server,acceptor0,2}, > {proc_lib,init_p_do_apply,3}]} > > Any hints on what's going on? I'm guessing you're giving Yaws some bad values to be returned as part of the response body from your .yaws code. Can you either post your .yaws code or send me a copy offline? --steve |
From: Michal D. <mic...@gm...> - 2010-12-22 01:41:46
|
On Tue, Dec 21, 2010 at 4:51 PM, Steve Vinoski <vi...@ie...> wrote: > On Tue, Dec 21, 2010 at 12:07 PM, Michal D. <mic...@gm...> > wrote: > > Hi, > > > > I'm trying to write a fairly simple AJAX multiplayer game in Yaws. I > spawn > > a seperate process to handle the server state across all clients. There > are > > two .yaws files, both called from JavaScript by xml http request objects > via > > GET. > > > > submit.yaws - query string holds a an action performed by the player > > (affects state server, client ignores any response). > > request.yaws - subscribes to state server modification notifications, > then > > wais for a message from the state server with the new state. > > > > The problem is that once submit.yaws is accessed a process dies > (different > > pid from processes handling submit.yaws or request.yaws). After this, the > > request.yaws seems to hang and no new updates come in. The process that > dies > > shows up with the following message: > > > > =ERROR REPORT==== 21-Dec-2010::12:03:56 === > > Yaws process died: > {function_clause,[{yaws_server,binary_size,[0,<0.71.0>]}, > > {yaws_server,binary_size,2}, > > {yaws_server,deliver_accumulated,5}, > > {yaws_server,finish_up_dyn_file,2}, > > {yaws_server,aloop,3}, > > {yaws_server,acceptor0,2}, > > {proc_lib,init_p_do_apply,3}]} > > > > Any hints on what's going on? > > I'm guessing you're giving Yaws some bad values to be returned as part > of the response body from your .yaws code. Can you either post your > .yaws code or send me a copy offline? > > --steve > Hi Steve, Thanks for taking an interest in my problem. I created a toy version that will hopefully be easier to debug but it doesn't have exactly the same problem. Same: sometimes 'reset' will hang the counter. Different: real page always seems to hang, toy does not crash any processes. Hopefully it will give you an idea of what's going on though. I'll send the real code if still necessary. Sorry for the longish message, this is as much as I could get it down. === yaws/request.yaws ========================= <erl> out(A) -> io:put_chars("request.yaws hello\n\n"), % Start the game server if it's not running yet. ebin:start_server(), % Send the request. global:send(stateServer, {request, self()}), receive Result -> {html, Result} end. </erl> === yaws/submit.yaws ========================= <erl> out(A) -> io:put_chars("submit.yaws hello\n\n"), % Start the game server if it's not running yet. ebin:start_server(), % Send submit. global:send(stateServer, submit), {html, ""}. </erl> === ebin/ebin.erl ============================== -module(ebin). -export([state_server/2, start_server/0]). term_to_str(T) -> lists:flatten(io_lib:format("~p", [T])). % Start the game server if it's not running yet. start_server() -> case global:whereis_name(stateServer) of undefined -> Pid = spawn(ebin, state_server, [0, []]), global:register_name(stateServer, Pid), erlang:start_timer(1000, Pid, {}); _ -> {} end. state_server(Count, Requests) -> receive {request, Pid} -> state_server(Count, [Pid|Requests]); submit -> lists:map(fun(Pid) -> Pid ! term_to_str(Count) end, Requests), state_server(0, []); {timeout, _, _} -> erlang:start_timer(1000, self(), {}), lists:map(fun(Pid) -> Pid ! term_to_str(Count) end, Requests), state_server(Count+1, []); X -> io:put_chars("server got unkown message:"), io:write(X), io:put_chars("\n\n") end. === index.html ===================================== <html> <head> <script type="text/javascript"> function NewXmlHttpRequest() { var xmlhttp; // code for IE7+, Firefox, Chrome, Opera, Safari if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } // code for IE6, IE5 else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.isReady = function() { // xmlhttp.status is defined once xmlhttp.readyState >= 2 return this.readyState === 4 && this.status === 200; } return xmlhttp; } function request() { xmlhttp = NewXmlHttpRequest(); xmlhttp.onreadystatechange = function() { if (xmlhttp.isReady()) { document.getElementById("counter").innerHTML = xmlhttp.responseText; request(); } } // Send request off to server xmlhttp.open("GET", "yaws/request.yaws", true); xmlhttp.send(); } function submit() { // Callback xmlhttp = NewXmlHttpRequest(); xmlhttp.onreadystatechange = function() {} // Send request off to server xmlhttp.open("GET","yaws/submit.yaws", true); xmlhttp.send(); } </script> </head> <body> <div id="counter">?</div> <input type="button" value="Reset" onclick="submit()"> <div id="debug">_debug_</div> <script type="text/javascript">request()</script> </body> </html> === yaws.conf ============================== ebin_dir = "ebin/" <server localhost> port = 8080 listen = 127.0.0.1 docroot = /home/mkd/www/prewix_bug </server> Michal |
From: Steve V. <vi...@ie...> - 2010-12-22 07:47:26
|
On Tue, Dec 21, 2010 at 8:41 PM, Michal D. <mic...@gm...> wrote: > > Thanks for taking an interest in my problem. I created a toy version that > will hopefully be easier to debug but it doesn't have exactly the same > problem. Same: sometimes 'reset' will hang the counter. Different: real > page always seems to hang, toy does not crash any processes. Hopefully it > will give you an idea of what's going on though. I'll send the real code if > still necessary. I think the problem is in your JavaScript. You have the isReady() function: > xmlhttp.isReady = function() { > // xmlhttp.status is defined once xmlhttp.readyState >= 2 > return this.readyState === 4 && this.status === 200; > } which you use to call request() recursively, as shown below: > function request() { > xmlhttp = NewXmlHttpRequest(); > xmlhttp.onreadystatechange = function() { > if (xmlhttp.isReady()) { > document.getElementById("counter").innerHTML = > xmlhttp.responseText; > > request(); > } > } > > // Send request off to server > xmlhttp.open("GET", "yaws/request.yaws", true); > xmlhttp.send(); > } but if xmlhttp.isReady() returns false, then the counter on the page isn't updated and request() never gets called again, which in turn means request.yaws is never retrieved again and things will appear to hang. --steve |
From: Michal D. <mic...@gm...> - 2010-12-22 16:48:44
|
> > I think the problem is in your JavaScript. You have the isReady() function: > > > xmlhttp.isReady = function() { > > // xmlhttp.status is defined once xmlhttp.readyState >= 2 > > return this.readyState === 4 && this.status === 200; > > } > > which you use to call request() recursively, as shown below: > > > function request() { > > xmlhttp = NewXmlHttpRequest(); > > xmlhttp.onreadystatechange = function() { > > if (xmlhttp.isReady()) { > > document.getElementById("counter").innerHTML = > > xmlhttp.responseText; > > > > request(); > > } > > } > > > > // Send request off to server > > xmlhttp.open("GET", "yaws/request.yaws", true); > > xmlhttp.send(); > > } > > but if xmlhttp.isReady() returns false, then the counter on the page > isn't updated and request() never gets called again, which in turn > means request.yaws is never retrieved again and things will appear to > hang. > > Sure, that makes sense, but it seems to me that isReady() should eventually return true. Its return status signifies that the server has completed transferring data to the client. The callback itself is called multiple times as the transfer proceeds. The server takes a request and holds on to it until it wants to send back data so the client really should eventually get a response back? |
From: Steve V. <vi...@ie...> - 2010-12-22 19:01:41
|
On Wed, Dec 22, 2010 at 11:48 AM, Michal D. <mic...@gm...> wrote: > > Sure, that makes sense, but it seems to me that isReady() should eventually > return true. Its return status signifies that the server has completed > transferring data to the client. The callback itself is called multiple > times as the transfer proceeds. The server takes a request and holds on to > it until it wants to send back data so the client really should eventually > get a response back? I was running this in Firefox with Firebug enabled and watching the JavaScript console, and you can definitely see that it gets to the point where if you hit the reset button at just the right time, the request loop stops. I don't know if it's because the submit() function sets onreadystatechange to an empty function or what, but that's what I see. I also was running yaws interactively and was tracing the ebin module's functions in the erlang shell, and I didn't see anything going wrong with anything there. --steve |
From: Michal D. <mic...@gm...> - 2010-12-26 23:31:13
|
Hey Steve, I though I'd update you and the list on what actually transpired. On Wed, Dec 22, 2010 at 2:01 PM, Steve Vinoski <vi...@ie...> wrote: > On Wed, Dec 22, 2010 at 11:48 AM, Michal D. <mic...@gm...> > wrote: > > > > Sure, that makes sense, but it seems to me that isReady() should > eventually > > ... > > get a response back? > > I was running this in Firefox with Firebug enabled and watching the > JavaScript console, and you can definitely see that it gets to the > point where if you hit the reset button at just the right time, the > request loop stops. I don't know if it's because the submit() function > sets onreadystatechange to an empty function or what, but that's what > I see. > > The problem was that I was missing the 'var' keyword before defining my XMLHttpRequest objects. Had: xmlhttp = NewXMLHttpRequest(); Should have had: var xmlhttp = NewXMLHttpRequest(); Since I was creating them in two places I ended up clobbering one when I created the other and vice-versa. I found it almost impossible to track this down - the major clue came when I made the server side 'submit' code return something and that showed up in the 'request' output in the client. A strict hint that something funky was going on with the onreadystate callback. The crash that was happening in the server itself never got tracked down. It didn't seem to affect the state of any of the processes and so it remains a bit of a mystery. With rewriting and adding stuff it eventually went away. Thanks for your help Steve, Cheers, Michal |