eis / jboss-websocket-demo

Demo of WebSocket functionality in JBoss
MIT License
5 stars 7 forks source link

demo stops working after a while #2

Open tmescic opened 11 years ago

tmescic commented 11 years ago

The demo works fine at first. I open a Chrome instance, a Firefox instance and a IE10 instance. The messages are visible in all browsers. After a while (about 10-15 messages) the demo stops working (messages are not visible nor sent to other clients), and an exception is thrown in the JBOSS server log:

13:47:37,403 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/websocket-web-app].[fi.eis.applications.jboss.poc.websocket.servlets.MyWebSocketServlet]] 
(http-/127.0.0.1:8080-1) JBWEB000236: Servlet.service() for servlet fi.eis.applications.jboss.poc.websocket.servlets.MyWebSocketServlet threw exception: org.apache.tomcat.jni.Error: APR does not understand this error code
    at org.apache.tomcat.jni.Socket.sendbb(Native Method) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:843) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.coyote.http11.InternalAprOutputBuffer.flush(InternalAprOutputBuffer.java:307) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.coyote.http11.Http11AprProcessor.action(Http11AprProcessor.java:1045) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.coyote.Response.action(Response.java:190) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:347) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:316) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:98) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.atmosphere.jboss.websockets.oio.internal.protocol.ietf13.Hybi13Socket._writeTextFrame(Hybi13Socket.java:190) [jboss-as-websockets-0.4.jar:]
    at org.atmosphere.jboss.websockets.oio.internal.protocol.ietf13.Hybi13Socket.writeFrame(Hybi13Socket.java:267) [jboss-as-websockets-0.4.jar:
    at org.atmosphere.jboss.as.websockets.servlet.WebSocketDelegate.writeFrame(WebSocketDelegate.java:42) [jboss-as-websockets-0.4.jar:]
    at fi.eis.applications.jboss.poc.websocket.servlets.MyWebSocketServlet.writeMessageToSocket(MyWebSocketServlet.java:60) [classes:]
    at fi.eis.applications.jboss.poc.websocket.servlets.MyWebSocketServlet.writeMessageToSockets(MyWebSocketServlet.java:53) [classes:]
    at fi.eis.applications.jboss.poc.websocket.servlets.MyWebSocketServlet.onReceivedFrame(MyWebSocketServlet.java:97) [classes:]
    at org.atmosphere.jboss.as.websockets.servlet.WebSocketServlet.event(WebSocketServlet.java:171) [jboss-as-websockets-0.4.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilterEvent(ApplicationFilterChain.java:458) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.core.ApplicationFilterChain.doFilterEvent(ApplicationFilterChain.java:364) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.core.StandardWrapperValve.event(StandardWrapperValve.java:409) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.core.StandardContextValve.event(StandardContextValve.java:171) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.valves.ValveBase.event(ValveBase.java:185) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.core.StandardHostValve.event(StandardHostValve.java:247) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.valves.ValveBase.event(ValveBase.java:185) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.core.StandardEngineValve.event(StandardEngineValve.java:121) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.catalina.connector.CoyoteAdapter.event(CoyoteAdapter.java:228) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.coyote.http11.Http11AprProcessor.event(Http11AprProcessor.java:767) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.event(Http11AprProtocol.java:565) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:2030) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
    at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_41]

I'm using JBOSS EAP 6.1 Alpha (same thing on beta) on Windows 7 64 bit, Java 1.6.0_41

eis commented 11 years ago

I can confirm this to be a real issue. I've assumed it as a problem of alpha-stage websocket support or APR. The issue seems to show up in other platforms when running JBoss as well.

tmescic commented 11 years ago

Any idea what could be causing this, or is there a workaround or a dirty fix for this? I was planning to use this demo as a basis for my own app, which would be deployed on JBOSS and it would broadcast messages to all connected clients - basically a one way communication channel. Initially, i used Atmosphere framework but i'm having OutOfMemory errors so i'm forced to consider other options. Hope this is fixable somehow...

eis commented 11 years ago

I tested and it is caused by jboss-websocket not detecting all possible websocket frame types and closing the connection on any invalid frames. You can see the problematic commit at this checkin. If you revert to websocket 0.3, or use a fork that reverts that commito old behaviour, it works just fine - it drops the invalid frame that seems to occur now and then but websocket connection will not close. I think it's an okayish workaround, especially as the problematic frame seems to be some kind of "ping" frame from browser. I'll do that change on this demo as well.

eis commented 11 years ago

I can see the issue occurring sometimes still, but not nearly as often at least... I cannot reproduce the problem with any specific steps and I can now chat pretty much as much as I want to.

tmescic commented 11 years ago

ok thanks, i am testing it right now. I'm using the snapshot version of jboss-as-websockets without the commit that is causing the problems. It seems to be working fine so far, i've got a lot of "unknown frame type" errors in the server.log but that's expected.

tmescic commented 11 years ago

yes, it breaks after it's running for a while. The big problem is that after it breaks, it stops working until the jboss instance is restarted (browser refresh doesn't help). Do you think that there is a way that it can detect when it's broken and recover?

eis commented 11 years ago

Well, more analysis would be needed as to why it breaks. JBoss is expected to have actual, supported websocket feature in AS8 (along with JEE7 specification) so for production-quality we might have to wait until then :(

guelzimtr commented 9 years ago

Hello,

I am running into this issue and I have to restart the server JBoss when it occurs . Any solution for it yet ?

eis commented 9 years ago

No, as nobodys working on it. Feel free to take a look and try to debug the issue. This is/was just a Proof Of Concept that this can be done. Sorry.

an01f01 commented 9 years ago

I know what the issue is and a fix/workaround. The problem is on the websocket implementation, it never calls onSocketClosed when a socket is closed, it instead sends a CloseFrame. So to fix this on the example change the following:

@Override protected void onSocketClosed(WebSocket socket) { this.sockets.remove(socket.getSocketID()); log.infof("Websocket closed :( [%s]", socket.getSocketID()); }

to

@Override protected void onSocketClosed(WebSocket socket) { // do nothing }

and

@Override protected void onReceivedFrame(WebSocket socket) { try { final Frame frame = socket.readFrame(); log.infof("Got a frame [%s] from socket [%s]", frame, socket.getSocketID()); if (frame instanceof TextFrame) { final String text = ((TextFrame) frame).getText(); log.infof("Got message %s", text); Pair<Long,String> infoPair = new ImmutablePair<Long, String>(System.currentTimeMillis(), text); MyWebSocketServlet.this.informationStorage.add(infoPair); writeMessageToSockets(MyWebSocketServlet.this.sockets, infoPair); / if ("Hello".equals(text)) { socket.writeFrame(TextFrame.from("Hey, there!")); } / } } catch (IOException ex) { log.error("Issue reading frame: " + ex.getMessage()); } }

to

@Override protected void onReceivedFrame(WebSocket socket) { try { final Frame frame = socket.readFrame(); log.infof("Got a frame [%s] from socket [%s]", frame, socket.getSocketID()); if (frame instanceof TextFrame) { final String text = ((TextFrame) frame).getText(); log.infof("Got message %s", text); Pair<Long,String> infoPair = new ImmutablePair<Long, String>(System.currentTimeMillis(), text); MyWebSocketServlet.this.informationStorage.add(infoPair); writeMessageToSockets(MyWebSocketServlet.this.sockets, infoPair); / if ("Hello".equals(text)) { socket.writeFrame(TextFrame.from("Hey, there!")); } / } else if (frame instanceof CloseFrame) { this.sockets.remove(socket.getSocketID());
log.infof("Websocket closed :( [%s]", socket.getSocketID()); } } catch (IOException ex) { log.error("Issue reading frame: " + ex.getMessage()); } }

This will solve the problem, which to explain further, gets triggered by the outputstream trying to flush data to a close socket/connection... I was trying to fix the issue on implementation and then realized to do it the other way around. This is thanks to the example from Mike Brock (https://github.com/mikebrock/jboss-websockets) that does not triggers any issue like this.

Hope this helps! -Alessandro