I have been working on a feature that makes use of technologies such as WebSocket, Kafka Streams to can serve data incrementally in a streaming fashion.
I can talk more about the interesting challeneges we encountered and how we addresses different issues. But for this post, I would like to have a general discussion about how to keep your websocket session alive.
Basics of WebSocket
The WebSocket protocol spec is specified at RFC6455
The basic idea is to enable a bi-directional communcation between client and server, without the need to oepning multiple http connections (e.g., long polling).
The Websocket only defines the protocol on the wire and allow you to choose the application level protocol by
There are Ping frame and Pong frame mechnism on the protocol level also. If a peer recieve ping from the other peer, it must reply with pong with the payload.
Stomp over WebSocket
WebSocket is too low level for any web framework to leverage to do things like interpreting messages or routing. Therefore, we need some higer level protocol to help.
All the JAVA implemented Websocket server/client follow JSR356.
JSR356 defines annotations for developer to easily create websocket endpoints, such as
@ClientEndpoint. After the Websocket connection has been established, a Session is created.
@OnOpen annotated method will be invoked indicating that the websocket is “opened”. When there is a message coming, the method annocated with
@OnMessage will be called.
There are also interface-drive approach to achieve the same.
Relationship with Http Session
Due to websocket is initiated with a http request, so there is asscoiate between the paritcular http session and any websocket established within that http session.
While I did find it in the doc, but from looking up on ther Internet, the expected behavior is that when the http session times out the websocket session also times out.
Keep Session Alive
Given the relation between http session and websocket connections, if you have a websocket session, and there is no client sending messages for a long time, your websocket session will be closed when the underlying http session being timed out (e.g., tomcat has 30mins by default).
Protocol-level Heartbeats may not Helping
Quote from the rfc6455
NOTE: A Ping frame may serve either as a keepalive or as a means to verify that the remote endpoint is still responsive.
This may explain a bit why protocol level heartbeat doesn’t extend your websocket session.While it is not a hard-written rule, it seems like protocol level ping/pong is more used for checking endpoint responsiveness. If used for this purpose, then it should not be used as indicator that user is still active.
Only messages sent from a user keep the session alive. This is because only messages coming from a user imply user activity. Received messages do not imply activity and, thus, do not renew the session expiration.
Found this from spring session document that supports this explanation.
Rejected Alternative - Change the Http Session Idle Timeout
Change the http session idle timeout to some longer value can mitigate the problem. But there is a side effect that you are changing timeout for all http sessions.
Finally, we have to implement our own ping/pong mechanism in application level. As based on our finding, user-sent message is the only solid proof that the user is alive. Thus the session will be kept alive.