0
votes

We have a JHipster microservice application with websockets. Currently, the main microservice (with frontend) is the one who send/receives messages through websockets relying on RabbitMQ as relay for the topics. We have configured Spring WebSockets + RabbitMQ like described in this blog post: http://djeison.me/2017/11/04/spring-websocket-rabbitmq/

Can I send a message to a topic from the other microservices in my architecture if I also configure this other microservices to relay to the same RabbitMQ instance?

Edit:

Here is the configuration class for Spring Websockets to relay on RabbitMQ. This is in the main microservice, where there are STOMP WebSockets with the frontend Angular application:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config
            .setApplicationDestinationPrefixes("/app")
            .enableStompBrokerRelay("/topic")
            .setRelayHost("localhost")
            .setRelayPort(61613)
            .setClientLogin("guest")
            .setClientPasscode("guest");
    }

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

}

My question is if I replicate this configuration in another microservice will it be able to reach the frontend application? Will it share the same WebSocket connections relaid to RabbitMQ? Thanks in advance.

1
How did you make the gateway to support websockets? As far as I know zuul proxy doesn't.Gaël Marziou
I have Spring Websockets configured like this class: github.com/selzlein/spring-websockets-rabbitmq-demo/blob/master/… using RabbitMQ as message broker following JHipster recommendation: jhipster.tech/using-websocketsdjeison
It is not clear to me how zuul proxy interferes heredjeison
You can send messages to RabbitMQ directly with any STOMP client. Don't replicate configuration, use STOMP client, for example Reactor2TcpStompClient from spring-messaging package. It will not share websocket connection, it make its' own connection to Rabbit.user1516873
@djeison Use it like js client library - create client, on connect acquire session and send or receive messages with session.send, session.subscribeuser1516873

1 Answers

0
votes

My question is if I replicate this configuration in another microservice will it be able to reach the frontend application?

Short answer is yes, but please see some clarifications below.

Will it share the same WebSocket connections relaid to RabbitMQ?

No, it won't. Any other microservice will have to connect and send messages to RabbitMQ.

Here are some options to send messages to a websocket from outside a "gateway" app:

  1. Setup a stomp broker relay and use SimpMessagingTemplate (spring-messaging)

Note that you don't need a stomp endpoint, only a broker relay. So the config could be:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableStompBrokerRelay("/topic")
    }
}

To send a message:

simpMessagingTemplate.convertAndSend("/topic/route", payload);

If your payload is an object and it should be serialized as json, you can add Jackson as a dependency, in that case AbstractWebSocketMessageBrokerConfigurer will create a json converter for you (it also supports String and byte[] out of the box).

  1. Use RabbitTemplate (spring-amqp)

Example config with spring-boot-starter-amqp as a dependency:

@Configuration
public class RabbitConfiguration {

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        Jackson2JsonMessageConverter messageConverter = new 
        Jackson2JsonMessageConverter();
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(messageConverter);
        return rabbitTemplate;
    }
}

Send a message:

rabbitTemplate.convertAndSend("amq.topic", "route", payload);
  1. As mentioned in the comments, we can use a StompSession (spring-integration-stomp)

A config, having spring-integration-stomp as a dependency:

@Configuration
@EnableIntegration
public class StompConfiguration {

    @Bean
    public ReactorNettyTcpStompClient stompClient() {
        ReactorNettyTcpStompClient stompClient = new ReactorNettyTcpStompClient("127.0.0.1", 61613);
        stompClient.setMessageConverter(new MappingJackson2MessageConverter());
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.afterPropertiesSet();
        stompClient.setTaskScheduler(taskScheduler);
        stompClient.setReceiptTimeLimit(5000);
        return stompClient;
    }

    @Bean
    public StompSessionManager stompSessionManager() {
        ReactorNettyTcpStompSessionManager stompSessionManager = new ReactorNettyTcpStompSessionManager(stompClient());
        stompSessionManager.setAutoReceipt(true);
        return stompSessionManager;
    }
}

Send a message:

stompSessionManager.connect(new StompSessionHandlerAdapter() {
    @Override
    public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
        session.send("/topic/route", messageDto);
    }
});

Here's a Github repo with a working example of a "gateway" application, to where the web socket connections are made, and separate applications sending messages to RabbitMQ "websocket queues" using 3 methods described above. It also addresses some issues regarding user/session destinations.