Stomp via websocket using Spring and sockJS message lost

Client side javascript I have

stomp.subscribe("/topic/path", function (message) { console.info("message received"); }); 

And server side

 public class Controller { private final MessageSendingOperations<String> messagingTemplate; ๏ผ Autowired public Controller(MessageSendingOperations<String> messagingTemplate) { this.messagingTemplate = messagingTemplate; } @SubscribeMapping("/topic/path") public void subscribe() { LOGGER.info("before send"); messagingTemplate.convertAndSend(/topic/path, "msg"); } } 

From this setting, I sometimes (approximately once per 30 pages updated) experience a message, which means that I see neither the message โ€œreceivedโ€ on the client side, nor the web feed using the Chrome debugging tool.

"before sending" is always registered on the server side.

It seems that MessageSendingOperations is not ready when I call it in the subscribe () method. (if I set Thread.sleep (50), before calling messagingTemplate.convertAndSend the problem will disappear (or will be reproduced much less often))

I wonder if someone has experienced the same thing before, and if there is an event that can tell me that MessageSendingOperations is ready or not.

+6
source share
2 answers

The problem you are facing by default is clientInboundChannel , which is ExecutorSubscribableChannel by default.

It has 3 subscribers :

 0 = { SimpleBrokerMessageHandler@5276 } "SimpleBroker[DefaultSubscriptionRegistry[cache[0 destination(s)], registry[0 sessions]]]" 1 = { UserDestinationMessageHandler@5277 } "UserDestinationMessageHandler[DefaultUserDestinationResolver[prefix=/user/]]" 2 = { SimpAnnotationMethodMessageHandler@5278 } "SimpAnnotationMethodMessageHandler[prefixes=[/app/]]" 

which are called inside taskExecutor , therefore, asynchronously.

The first one here ( SimpleBrokerMessageHandler (or StompBrokerRelayMessageHandler ), if you use broker-relay ), is responsible for registering the subscription for topic .

Your operation messagingTemplate.convertAndSend(/topic/path, "msg") can be performed before registering a subscription for this WebSocket session, as they are executed in separate threads. Therefore, the broker handler does not know how to send a message to the session.

@SubscribeMapping can be configured using the return method, where the result of this method will be sent as a response to this subscription function on the client.

NTN

+4
source

A little late, but I thought I'd add my solution. I had the same problem when the subscription was not registered before I sent the data through the messaging template. This question was rare and unpredictable due to a race with DefaultSubscriptionRegistry .

Unfortunately, I could not just use the return @SubscriptionMapping method because we used a custom object @SubscriptionMapping that dynamically changed depending on the type of user (essentially filtering attributes).

I searched Spring code and found that SubscriptionMethodReturnValueHandler was responsible for sending the return value of the signatures and had a different messagingTemplate file than the autowired SimpMessagingTemplate my asynchronous controller !!

So, the solution was autwiring MessageChannel clientOutboundChannel in my asynchronous controller and used this to create a SimpMessagingTemplate . (You cannot directly connect it, because you just get a template for the broker).

In the subscription methods, I then used the direct template, while in other methods I used the template that went to the broker.

0
source

Source: https://habr.com/ru/post/984102/


All Articles