Skip to content

exception during websocket client close [SPR-14721] #19286

Closed
@spring-projects-issues

Description

@spring-projects-issues

Prashant Deva opened SPR-14721 and commented

To reproduce:

Keep the websocket client running and shutdown the server.

Here is the setup and stop code -

class MyWS {
 void setup() throws ExecutionException, InterruptedException
    {

        WebSocketContainer webSocketContainer = new MyContainerProvider().create();
        List<Transport> transports = new ArrayList<Transport>(1);
        transports.add(new WebSocketTransport(new StandardWebSocketClient(webSocketContainer)));

        SockJsClient sockJsClient = new SockJsClient(transports);
        sockJsClient.setMessageCodec(new StringMessageCodec());

        stompClient = new WebSocketStompClient(sockJsClient);
        stompClient.setMessageConverter(new StringMessageConverter());
        stompClient.start();

        stompClient.connect(WS_URL, new MyStompSessionHandler());
    }

void stop()
    {
        StompSession stompSession = this.stompSession;
        if(stompSession!=null)
        {
            try
            {
                if(stompSession.isConnected())
                {
                    stompSession.disconnect();
                    Log.trace("Disconnecting from websocket");
                }
            } catch (Exception e)
            {
                Log.debug("error disconnecting", e);
            }
            this.stompSession = null;
        }
    }

private class MyStompSessionHandler extends StompSessionHandlerAdapter
    {
        @Override
        public void afterConnected(StompSession session, StompHeaders connectedHeaders)
        {
            MyWS.this.stompSession = session;
        }

        @Override
        public void handleFrame(StompHeaders headers, Object payload)
        {
            super.handleFrame(headers, payload);
        }

        @Override
        public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception)
        {
            Log.debug("Exception in realtime socket", exception);
        }

        @Override
        public void handleTransportError(StompSession session, Throwable exception)
        {
            MyWS.this.stop();
        }
    }




}

Here is the exception:

2016-09-15 09:48:25,909 [Grizzly(1)] DEBUG   -  error disconnecting
java.com.chronon.apm.libs.org.springframework.messaging.MessageDeliveryException: nested exception is java.lang.IllegalStateException: WebSocketClientSockJsSession[id='1f1aafad087b4cc78047f42b47b2ea3f, url=http://127.0.0.1:8082/wsgame] is not open, current state=CLOSED
	at java.com.chronon.apm.libs.org.springframework.messaging.simp.stomp.DefaultStompSession.execute(DefaultStompSession.java:277)
	at java.com.chronon.apm.libs.org.springframework.messaging.simp.stomp.DefaultStompSession.disconnect(DefaultStompSession.java:326)
	at java.com.chronon.apm.realtime.SpringWS.stop(SpringWS.java:88)
	at java.com.chronon.apm.realtime.SpringWS$MyStompSessionHandler.handleTransportError(SpringWS.java:190)
	at java.com.chronon.apm.libs.org.springframework.messaging.simp.stomp.DefaultStompSession.handleFailure(DefaultStompSession.java:444)
	at java.com.chronon.apm.libs.org.springframework.messaging.simp.stomp.DefaultStompSession.afterConnectionClosed(DefaultStompSession.java:459)
	at java.com.chronon.apm.libs.org.springframework.web.socket.messaging.WebSocketStompClient$WebSocketTcpConnectionHandlerAdapter.afterConnectionClosed(WebSocketStompClient.java:354)
	at java.com.chronon.apm.libs.org.springframework.web.socket.sockjs.client.AbstractClientSockJsSession.afterTransportClosed(AbstractClientSockJsSession.java:321)
	at java.com.chronon.apm.libs.org.springframework.web.socket.sockjs.client.WebSocketTransport$ClientSockJsWebSocketHandler.afterConnectionClosed(WebSocketTransport.java:172)
	at java.com.chronon.apm.libs.org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.onClose(StandardWebSocketHandlerAdapter.java:141)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusEndpointWrapper.onClose(TyrusEndpointWrapper.java:1259)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusWebSocket.onClose(TyrusWebSocket.java:130)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.ProtocolHandler.close(ProtocolHandler.java:469)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusWebSocket.close(TyrusWebSocket.java:264)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusWebSocket.close(TyrusWebSocket.java:274)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusRemoteEndpoint.close(TyrusRemoteEndpoint.java:495)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusSession.close(TyrusSession.java:233)
	at java.com.chronon.apm.libs.org.springframework.web.socket.adapter.standard.StandardWebSocketSession.closeInternal(StandardWebSocketSession.java:217)
	at java.com.chronon.apm.libs.org.springframework.web.socket.adapter.AbstractWebSocketSession.close(AbstractWebSocketSession.java:139)
	at java.com.chronon.apm.libs.org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.tryCloseWithError(ExceptionWebSocketHandlerDecorator.java:94)
	at java.com.chronon.apm.libs.org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:113)
	at java.com.chronon.apm.libs.org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42)
	at java.com.chronon.apm.libs.org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:81)
	at java.com.chronon.apm.libs.org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:78)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusSession.notifyMessageHandlers(TyrusSession.java:576)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusEndpointWrapper.onMessage(TyrusEndpointWrapper.java:879)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.TyrusWebSocket.onMessage(TyrusWebSocket.java:216)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.frame.TextFrame.respond(TextFrame.java:139)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.core.ProtocolHandler.process(ProtocolHandler.java:807)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.client.TyrusClientEngine$TyrusReadHandler.handle(TyrusClientEngine.java:747)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.container.grizzly.client.GrizzlyClientFilter$ProcessTask.execute(GrizzlyClientFilter.java:476)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.container.grizzly.client.TaskProcessor.processTask(TaskProcessor.java:114)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.container.grizzly.client.TaskProcessor.processTask(TaskProcessor.java:91)
	at java.com.chronon.apm.libs.org.glassfish.tyrus.container.grizzly.client.GrizzlyClientFilter.handleRead(GrizzlyClientFilter.java:272)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:526)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
	at java.com.chronon.apm.libs.org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: WebSocketClientSockJsSession[id='1f1aafad087b4cc78047f42b47b2ea3f, url=http://127.0.0.1:8082/wsgame] is not open, current state=CLOSED
	at java.com.chronon.apm.libs.org.springframework.util.Assert.state(Assert.java:392)
	at java.com.chronon.apm.libs.org.springframework.web.socket.sockjs.client.AbstractClientSockJsSession.sendMessage(AbstractClientSockJsSession.java:139)
	at java.com.chronon.apm.libs.org.springframework.web.socket.messaging.WebSocketStompClient$WebSocketTcpConnectionHandlerAdapter.send(WebSocketStompClient.java:383)
	at java.com.chronon.apm.libs.org.springframework.messaging.simp.stomp.DefaultStompSession.execute(DefaultStompSession.java:274)
	... 47 more

The exception is thrown on this line:

stompSession.disconnect();

However, as you can see I check to see if the session is connected using the isConnected() call.
The code should not throw an exception if isConnected() was checked before calling disconnect()


Affects: 4.2.6

Issue Links:

Referenced from: commits 62b02c2, 99c7917, 81f6c22

Backported to: 4.2.8

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: backportedAn issue that has been backported to maintenance branchestype: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions