Silvio127 / gwt-comet

Automatically exported from code.google.com/p/gwt-comet
0 stars 0 forks source link

Dead lock between CometServletResponseImpl#terminate() and getSession() #31

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Run the server
2. After a few connections and disconnections the server has no more available 
threads

What is the expected output? What do you see instead?
connections ordered to be closed should be closed

What version of the product are you using? On what operating system?
<dependency>
  <groupId>com.thales.socialnetwork.cots.net.zschech</groupId>
  <artifactId>gwt-comet</artifactId>
  <version>1.2.3</version>
</dependency>

Please provide any additional information below.
My understanding is that the comet session notifies the client and blocks 
waiting it to end, in that process if a call to 
CometServletResponseImpl#terminate() is executed, a new thread (that is get to 
handle the request) attempts to aquire the lock to close the session (that is 
waiting for an anwser).

'''the stack traces are: '''

java.lang.Thread.State: BLOCKED (on object monitor)

at 
net.zschech.gwt.comet.server.impl.CometServletResponseImpl?.terminate(CometServl
etResponseImpl?.java:287)

waiting to lock <0x00000000cab11a28> (a 
net.zschech.gwt.comet.server.impl.HTTPRequestCometServletResponse) at 
net.zschech.gwt.comet.server.impl.CometServletResponseImpl?.tryTerminate(CometSe
rvletResponseImpl?.java:300) at 
net.zschech.gwt.comet.server.impl.CometServletResponseImpl?.initiate(CometServle
tResponseImpl?.java:227) 
locked <0x00000000ca3b2bb8> (a 
net.zschech.gwt.comet.server.impl.HTTPRequestCometServletResponse) at 
net.zschech.gwt.comet.server.CometServlet?.doCometImpl(CometServlet?.java:137) 
at net.zschech.gwt.comet.server.CometServlet?.doGet(CometServlet?.java:108) at 
com.thales.socialnetwork.webappgwt.server.ClientNotifierServlet?.doGet(ClientNot
ifierServlet?.java:39) at 
javax.servlet.http.HttpServlet?.service(HttpServlet?.java:621) 

'''and'''

java.lang.Thread.State: BLOCKED (on object monitor)

at 
net.zschech.gwt.comet.server.impl.CometServletResponseImpl?.getSession(CometServ
letResponseImpl?.java:133)

waiting to lock <0x00000000c43d7300> (a 
net.zschech.gwt.comet.server.impl.EventSourceCometServletResponse?) at 
com.thales.socialnetwork.webappgwt.server.ClientNotifierServlet?.doComet(ClientN
otifierServlet?.java:49) at 
net.zschech.gwt.comet.server.CometServlet?.doCometImpl(CometServlet?.java:144) 
at net.zschech.gwt.comet.server.CometServlet?.doGet(CometServlet?.java:108) at 
com.thales.socialnetwork.webappgwt.server.ClientNotifierServlet?.doGet(ClientNot
ifierServlet?.java:39) at 
javax.servlet.http.HttpServlet?.service(HttpServlet?.java:621) 

In my code I have nothing special:
'''ClientfactoryImpl.java'''

    @Override
    public CometClient startCometClient() {
        // NOTE this may cause dead locks because closing is happening in the same "notification" process but tries to close
        // the same resource in a different request (different thread)
        stopCometClient();

        if (getEnvironment().getConnectedUser() == null) {
            System.out.println("skipping comet creation: no user logged in");
            return null;
        }

        CometSerializer serializer = GWT.create(NotificationMessageCometSerializer.class);
        environment.setLastHeartBeatNow();
        cometClient = new CometClient(GWT.getModuleBaseURL() + "comet", serializer, new CometCentralListener(this));
        // NOTE zied : you can disable comet for tests by commenting the next line
        cometClient.start();
        return cometClient;
    }

    /**
     * stops current comet client
     * 
     */
    @Override
    public void stopCometClient() {
        if (cometClient != null) {
            cometClient.stop();
            cometClient = null;
        }
    }

'''And in RequestTransport, I check on each click that I didn't miss too much 
heartbeats (if I did, I assume the connection is dead)'''

    @Override
    public void send(String payload, final TransportReceiver receiver) {

        TransportReceiver transportReceiver = new TransportReceiver() {

            @Override
            public void onTransportSuccess(String tPayload) {
                receiver.onTransportSuccess(tPayload);
                Environment environment = clientFactory.getEnvironment();
                clientFactory.getStatusView().setText(
                        environment.isCometAlive() ? "ALIVE since " + new Date(environment.getLastHeartBeat()) : "WAS DEAD since "
                                + new Date(environment.getLastHeartBeat()) + " restarted");
                // NOTE this could cause comet dead locks if a received comet event is the cause for this call
                // if connection was lost, attempt to reconnect on first request factory call
                if (!environment.isCometAlive()) {
                    environment.setLastHeartBeatNow();
                    GWT.log("User comet session was dead. Awakening...");
                    clientFactory.startCometClient();
                    notificationService.setStatus(GwtOnLineStatus.ONLINE, new AsyncCallback<Void>() {

                        @Override
                        public void onSuccess(Void result) {
                            GWT.log("User reconnected to comet");
                        }

                        @Override
                        public void onFailure(Throwable caught) {
                            GWT.log("User unable to reconnect to comet");
                        }
                    });
                }
            }

            @Override
            public void onTransportFailure(ServerFailure tFailure) {
                receiver.onTransportFailure(tFailure);
            }
        };
        super.send(payload, transportReceiver);
    }

Any ideas please?

Best regards,
Zied Hamdi

Original issue reported on code.google.com by zhamdi.into on 5 Mar 2012 at 4:44

GoogleCodeExporter commented 9 years ago
I have some news:

It seems the problem happens with tomcat 7 but not with jetty 6. 

I'm wondering if it's not the behavior of the servlet3 specification which 
doen' force the same thread to handle a request for all its lifetime. Maybe a 
thread creates a session and onother tries to terminate it. If the scenario 
happens between two threads and two sessions we have two dead locks.

Do you think it's a possibility???

Original comment by zhamdi.into on 5 Mar 2012 at 6:06