Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StompSessionHandler not calling handleFrame in afterConnected block?

I have a fairly simple setup to test Stomp support in Spring.

I was planning on using JS to send messages to the queue and receive and handle them in Spring app. However, it doesn't seem to work for some reason.

JS client:

var ws = new SockJS('/hello');
client = Stomp.over(ws);
...
client.subscribe('jms.queue.test', function(message) {}
...
client.send("jms.queue.test", {}, "message");

Spring config (mostly useless at the moment, since i don't use /app destination):

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableStompBrokerRelay("jms.topic", "jms.queue");
        config.setApplicationDestinationPrefixes("/app");
        config.setPathMatcher(new AntPathMatcher("."));
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/hello").withSockJS();
    }
}

Spring Boot App:

@Component
public class BusinessLogic implements CommandLineRunner {

    @Autowired
    hulloController controller;

    @Override
    public void run(String... args) throws Exception {
        stuff(args);
    }

    public void stuff(String[] args) throws InterruptedException {
        Thread.sleep(20000);//sleep while spring boot fully initializes
        controller.waitForGreet();
    }
}

Controller (not a real @Controller, i don't plan to use MVC):

@Component
public class hulloController {

    private SimpMessagingTemplate template;

    @Autowired
    StompSessionHandler handler;

    @Autowired
    public hulloController(SimpMessagingTemplate template) {
        this.template = template;
    }

    public void waitForGreet() {
        System.out.println("Entered Listener");

        WebSocketClient transport = new StandardWebSocketClient();
        WebSocketStompClient stompClient = new WebSocketStompClient(transport);
        stompClient.setMessageConverter(new StringMessageConverter());
        stompClient.connect("ws://127.0.0.1:61613/stomp", handler);
    }
}

And finally, the handler:

@Component
public class SessionHandler implements StompSessionHandler {
    @Override
    public void afterConnected(StompSession stompSession, StompHeaders stompHeaders) {
        System.out.println("Connected!");
        StompFrameHandler handler = new StompFrameHandler() {
            @Override
            public Type getPayloadType(StompHeaders stompHeaders) {
                return null;
            }

            @Override
            public void handleFrame(StompHeaders stompHeaders, Object o) {
                System.out.println("received " + o.toString());
            }
        };

        //StompSession.Subscription s = stompSession.subscribe("jms.queue.test", handler);

        stompSession.send("jms.queue.test", "hello!");
    }
    ...
}

If i comment the client.subscribe part, client.send works properly, message is received and rendered in JS, so the queue names and connection URL are fine. I also tried using SockJSClient as a Transport but it doesn't help.

When i send messages from JS, for about 1 or 2 minutes half of them isn't showing up (as it would be if the subscription would be working), then JS starts receiving 100% of the messages.

I've seen plenty of almost identical code on github today, and i just don't see what the issue might be here.

like image 553
Dmitry Korchemkin Avatar asked Sep 14 '25 19:09

Dmitry Korchemkin


2 Answers

So, apparently switching from implementing StompSessionHandler to extending StompSessionHandlerAdapter for my handler did the trick.

I have absolutely no idea why, but i guess this passage from Spring docs for StompSessionHandler is there for a reason:

"Implementations of this interface should consider extending StompSessionHandlerAdapter."

like image 125
Dmitry Korchemkin Avatar answered Sep 16 '25 08:09

Dmitry Korchemkin


 //StompSession.Subscription s = stompSession.subscribe("jms.queue.test", handler);

 stompSession.send("jms.queue.test", "hello!");

The STOMP over WebSocket is a an async protocol.

You call there subscribe and got to the send. There is no guaranty that the subscription will happen already, when you start to send something to that destination.

Consider to use StompSession.Subscription and its addReceiptTask() to send messages to the destination after the confirmation for the subscription.

And you should enable StompSession.setAutoReceipt(true) to make that working with your STOMP Broker.

like image 44
Artem Bilan Avatar answered Sep 16 '25 10:09

Artem Bilan