Spring STOMP via WebSockets not scheduling a heartbeat

We have a Spring connection through WebSockets, through which we pass a CONNECT frame:

 CONNECT\naccept-version:1.2\nheart-beat:10000,10000\n\n\u0000 

which confirms the handler, starts a new session and returns:

 CONNECTED version:1.2 heart-beat:0,0 

However, we want heartbeats to open the WebSocket. We do not use SockJS.

I went through the Spring message handler:

 StompHeaderAccessor [headers={simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={accept-version=[1.2], heart-beat=[5000,0]}, simpSessionAttributes={}, simpHeartbeat=[ J@5eba717 , simpSessionId=46e855c9}] 

After it receives a heart-beat (its own header), it sets what looks like a memory address simpHeartbeat=[ J@5eba717 , simpSessionId=46e855c9}]

It should be noted that after the broker authenticates:

Processing CONNECT session=46e855c9 (sessionId here is different from simpSessionId)?

When I started the earlier TRACE debugging, I saw a "Runout Planning ..." notification or something like that ... although I don’t see it now?

Any idea what is going on?

thanks

I found an explanation in the documentation :

SockJS Task Scheduler Statistics from the Task Flow Pool SockJS Scheduler, which is used to send a heartbeat. Note that when the heartbeat is discussed at the STOMP level, SockJS heartbeats are disabled.

Are SockJS heart beats different from STOMP heart attacks?

+7
spring-websocket stomp
source share
3 answers

Yes SockJS heartbeats are different. Basically the same thing, but their goal in the SockJS protocol is to make sure that the connection does not look like a dead one, in which case proxies can close it actively. In a more general case, the heartbeat allows each side to detect connectivity problems, actively and clear resources.

When using STOMP and SockJS at the transport level, there is no need to have both of them, so SockJS heartbeats are disabled if STOMP pulses are used. However, you are not using SockJS here.

You do not show any configuration, but I assume that you are using a built-in simple broker that does not automatically send a pulse. When you configure it, you will see the option to enable beats, and also set the task scheduler.

 @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { // ... } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableStompBrokerRelay(...) .setTaskScheduler(...) .setHeartbeat(...); } } 
+5
source share

We had the same problem with Spring, Websockets, STOMP, and Spring Sessions - no beating and Spring session may expire, and websocket does not receive messages on the server side. We ended up enabling STOMP heartbeats from the browser every 20,000 ms and add SimpMessageType.HEARTBEAT to the Spring sessionRepositoryInterceptor to keep Spring the last session time of the session updated on STOMP pulses without messages. We had to use the Abstract Session WebSocketMessageBrokerConfigurer as the base to enable the inline w861 session and websocket session. Spring guide , second example. In the official example, the Spring session is updated in the incoming CONNECT / MESSAGE / SUBSCRIBE / UNSUBSCRIBE messages, but not heartbeats, so we need to reconfigure 2 things - enable at least incoming heartbeats and adjust the Spring session to respond to websocket heartbeats

 public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> { @Autowired SessionRepositoryMessageInterceptor sessionRepositoryInterceptor; @Override public void configureMessageBroker(MessageBrokerRegistry config) { sessionRepositoryInterceptor.setMatchingMessageTypes(EnumSet.of(SimpMessageType.CONNECT, SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE, SimpMessageType.UNSUBSCRIBE, SimpMessageType.HEARTBEAT)); config.setApplicationDestinationPrefixes(...); config.enableSimpleBroker(...) .setTaskScheduler(new DefaultManagedTaskScheduler()) .setHeartbeatValue(new long[]{0,20000}); } } 

Another way we tried is to reimplement the SessionRepositoryMessageInterceptor function to update the time of the last w761 session on outgoing websocket messages and to support the websocket β†’ Spring session through listeners, but the code above did the trick.

+5
source share

By launching Spring 4.2, you can have full control on the server side of the heartbeat matching result using Stomp over SockJS with the built-in SimpleBroker:

 public class WebSocketConfigurer extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { ThreadPoolTaskScheduler te = new ThreadPoolTaskScheduler(); te.setPoolSize(1); te.setThreadNamePrefix("wss-heartbeat-thread-"); te.initialize(); config.enableSimpleBroker("/") /** * Configure the value for the heartbeat settings. The first number * represents how often the server will write or send a heartbeat. * The second is how often the client should write. 0 means no heartbeats. * <p>By default this is set to "0, 0" unless the {@link #setTaskScheduler * taskScheduler} in which case the default becomes "10000,10000" * (in milliseconds). * @since 4.2 */ .setHeartbeatValue(new long[]{heartbeatServer, heartbeatClient}) .setTaskScheduler(te); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint(.....) .setAllowedOrigins(....) .withSockJS(); } } 
+4
source share

All Articles