spring-projects / spring-projects/spring-framework

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

Open
#34,787 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: messaging status: waiting-for-triage
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with StandardWebSocketSession#closeInternal and follow the close callback through StandardWebSocketHandlerAdapter#onClose to StompSubProtocolHandler#afterSessionEnded. Compare the StandardWebSocketSession and AbstractSockJsSession ordering, then verify that a closing standard session does not produce the “No decoder for session id” exception after its decoder is removed.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
backend, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.