spring-framework icon indicating copy to clipboard operation
spring-framework copied to clipboard

Avoid “No decoder for session id” Exception if session is closed

Open piaorlm opened this issue 7 months ago • 0 comments

Hello, this is the same issue with https://github.com/spring-projects/spring-framework/issues/24842. Open another one since I can not reopen it because this issue has not been fixed eventually. It still happens occasionally when using org.springframework.web.socket.adapter.standard.StandardWebSocketSession.

The native org.apache.tomcat.websocket.wsSession will set its state finally to CLOSED after calling fireEndpointOnClose when calling StandardWebSocketSession#closeInternal. (tomcat-embed-websocket:10.1.39)

public class WsSession implements Session {
    ...
    public void doClose(CloseReason closeReasonMessage, CloseReason closeReasonLocal, boolean closeSocket) {
        if (!state.compareAndSet(State.OPEN, State.OUTPUT_CLOSING)) {
            return;
        }
        ...
        fireEndpointOnClose(closeReasonLocal);
        if (!state.compareAndSet(State.OUTPUT_CLOSING, State.OUTPUT_CLOSED) || closeSocket) {
            state.set(State.CLOSED);
            closeConnection();
        } else {
            sessionCloseTimeoutExpiry =
                    Long.valueOf(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(getSessionCloseTimeout()));
        }
        ...
    }
    ...
}

The method fireEndpoinOnClose will call the expression this.handler.afterConnectionClosed in org.springframework.web.socket.adapter.standar.StandardWebSocketHandlerAdapter#onClose.

Finally in org.springframework.web.socket.messaging.StompSubProtocolHandler#afterSessionEnded the decoder of the session will be removed.

However, during above process, the state of the session is still OUTPUT_ClOSING which is marked as true for isOpen method as below.

public class WsSession implements Session {
    ...
    @Override
    public boolean isOpen() {
        return state.get() == State.OPEN || state.get() == State.OUTPUT_CLOSING || state.get() == State.CLOSING;
    }
    ...
}

Therefore, with the fix in previous issue, when the decoder is null for the session, the session might still be in state of OUTPUT_CLOSING.


BTW. This does not happen when using SocketJsSession, because the state will be set to CLOSED, here, before calling afterConnectionClosed

piaorlm avatar Apr 21 '25 09:04 piaorlm