Message is not sent to all active subscribers when using spring-websocket and rabbitmq-stomp

2,003 views
Skip to first unread message

zhu kane

unread,
Mar 2, 2017, 5:21:04 AM3/2/17
to rabbitmq-users
I have a web app based on spring websocket over stomp(powered by spring boot 1.5.1). And I'm using Rabbitmq(3.6.6) with stomp plug-in as full feature broker.

According to the doc of stomp, the message with destination from /topic/ will be delivered to all active subscribers.

Topic Destinations 
 For simple topic destinations which deliver a copy
 of each message to all active subscribers
, destinations of the form
 /topic/<name> can be used. Topic destinations support all the routing
 patterns of AMQP topic exchanges.
 
 Messages sent to a topic destination that has no active subscribers
 are simply discarded.

But the behavior is NOT consistent with above declaration in my app!

I opened the same page in two browsers. Hence there are two clients connecting to the websocket server. Both of them subscribed the same destination starting with /topic/.

After I sent the message to destination /topic/<route key>, but only one client will receive the message. The two client will rotate to receive the messages from the same destination.


In my spring server side app, I send the messages to destination like below,

        @Secured(User.ROLE_USER)
   
@MessageMapping("/comment/{liveid}")
   
@SendTo("/topic/comment-{liveid}")
   
public CommentMessage userComment(@DestinationVariable("liveid") String liveid,
                                         
@AuthenticationPrincipal UserDetails activeUser, UserComment userComment) {
        logger
.debug("Receiving comment message '{}' of live '{}' from user '{}'.",
                userComment
,liveid, activeUser.getUsername());
       
final User user = userService.findByUsername(activeUser.getUsername()).get();
       
return CommentMessage.builder().content(userComment.getContent()).sender(user.getNickname())
               
.senderAvatar(user.getAvatar()).build();
   
}


In my client side, it subscribes the durable topic like below,

    $stomp.subscribe('/topic/comment-' + $scope.lives[i].id, function(payload, headers, res) {
                                   
// do something
                               
}, {
                                   
'durable': true,
                                   
'auto-delete': false
                               
});


Below is the configuration of websocket in my spring app,

    @Configuration
   
@EnableWebSocketMessageBroker


   
public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> {


   
@Value("${stompBroker.host:localhost}")
   
String brokerHost;
   
@Value("${stompBroker.port:61613}")
   
int brokerPort;
   
@Value("${stompBroker.login:guest}")
   
String brokerLogin;
   
@Value("${stompBroker.passcode:guest}")
   
String brokerPasscode;
   
@Value("${stompBroker.vhost:myvhost}")
   
String brokerVHost;


   
@Override
   
protected void configureStompEndpoints(StompEndpointRegistry registry) {
        registry
.addEndpoint("/live/ws").withSockJS();
   
}


   
@Override
   
public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry
.enableStompBrokerRelay("/topic/").setRelayHost(brokerHost).setRelayPort(
                brokerPort
).setSystemLogin(brokerLogin).setSystemPasscode(brokerPasscode).setVirtualHost(brokerVHost);


       
/**
         * Both of two subscribers can receive the message if using simple broker
        registry.enableSimpleBroker("/topic/");
         */

        registry
.setApplicationDestinationPrefixes("/app");
   
}


   
@Configuration
   
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
       
@Override
       
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
            messages
.simpDestMatchers("/app/*").hasRole("USER");
       
}


       
@Override
       
protected boolean sameOriginDisabled() {
           
return true;
       
}
   
}
   
}


In the management UI of RabbitMQ, I can see there is queue named 'stomp-xxxx' binding to amq.topic with clients' subscription 'comment-<liveid>'.



Below the debug output of stomp client ONE in browser, it sent both "first message" and "second message". But it only received "second message".

live_f84730c.js:36 Opening Web Socket...
live_f84730c.js:36 Web Socket Opened...
live_f84730c.js:36 >>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000

live_f84730c.js:36 <<< CONNECTED
server:RabbitMQ/3.6.6
session:session-Xu-7aNTIE6W30AgSEZQJAw
heart-beat:10000,10000
version:1.1
user-name:58b7e71f1dc9e83c4b2f1a7e

live_f84730c.js:36 connected to server RabbitMQ/3.6.6
live_f84730c.js:36 send PING every 10000ms
live_f84730c.js:36 check PONG every 10000ms
live_f84730c.js:36 <<< PONG
live_f84730c.js:36 >>> SUBSCRIBE
durable:true
auto-delete:false
id:sub-0
destination:/topic/watchinfo-581820bb19ed180005322ed6

live_f84730c.js:36 >>> SUBSCRIBE
durable:true
auto-delete:false
id:sub-1
destination:/topic/comment-581820bb19ed180005322ed6

live_f84730c.js:36 >>> SEND
priority:9
destination:/app/watch/581820bb19ed180005322ed6
content-length:2

{}
live_f84730c.js:36 <<< PONG
live_f84730c.js:36 >>> PING
live_f84730c.js:36 <<< PONG
live_f84730c.js:36 >>> SEND
priority:9
destination:/app/comment/581820bb19ed180005322ed6
content-length:27

{"content":"first message"}
live_f84730c.js:36 >>> PING
live_f84730c.js:36 >>> SEND
priority:9
destination:/app/comment/581820bb19ed180005322ed6
content-length:28

{"content":"second message"}
live_f84730c.js:36 <<< MESSAGE
subscription:sub-1
destination:/topic/comment-581820bb19ed180005322ed6
message-id:T_sub-1@@session-Xu-7aNTIE6W30AgSEZQJAw@@1
redelivered:false
content-type:application/json;charset=UTF-8
content-length:64

{"content":"second message","sender":"小琦","senderAvatar":""}
2live_f84730c.js:36 <<< PONG
live_f84730c.js:36 >>> PING
live_f84730c.js:36 <<< PONG
live_f84730c.js:36 >>> PING

The client TWO only received "first message",

<<< MESSAGE
subscription:sub-1
destination:/topic/comment-581820bb19ed180005322ed6
message-id:T_sub-1@@session-XjhlhlhhXoASjCkMf1_SBg@@8
redelivered:false
content-type:application/json;charset=UTF-8
content-length:63


{"content":"first message","sender":"小琦","senderAvatar":""}�


Is it a configuration issue or problem of RabbitMQ? Any more information you need it please let me know.

Thanks.

Kane

Michael Klishin

unread,
Mar 2, 2017, 5:50:53 AM3/2/17
to rabbitm...@googlegroups.com
We already changed the language on that page:

Topic routing matches topics used by publishers with topic patterns used by subscribers. It DOES NOT
route every message to every subscriber (that's how fanouts work).

--
You received this message because you are subscribed to the Google Groups "rabbitmq-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rabbitmq-users+unsubscribe@googlegroups.com.
To post to this group, send email to rabbitmq-users@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
MK

Staff Software Engineer, Pivotal/RabbitMQ

Arnaud Cogoluègnes

unread,
Mar 2, 2017, 6:01:08 AM3/2/17
to rabbitm...@googlegroups.com
You're using 2 durable subscriptions, with the same ID, the consumers become competitive consumers. You should either use non-durable subscriptions (which makes sense if the messages are about UI events) or stick with durable subscriptions, but with a different ID.

--

Michael Klishin

unread,
Mar 2, 2017, 6:05:53 AM3/2/17
to rabbitm...@googlegroups.com
To clarify this a bit more: subscriber ID is used to form queue name, so if you want each subscriber to get a copy, your resulting
topology should have 2 separate queues and not just 1. If you switch to non-durable subscriptions, queue names will be generated
by RabbitMQ in a way that's guaranteed to be unique in the cluster.

To post to this group, send email to rabbitm...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "rabbitmq-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rabbitmq-users+unsubscribe@googlegroups.com.
To post to this group, send email to rabbitmq-users@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

zhu kane

unread,
Mar 3, 2017, 7:15:28 AM3/3/17
to rabbitm...@googlegroups.com
Michael and Arnaud, thanks a lot for your kindly support.

I managed to make all clients receiving the messages when they subscribe same topic.

Either specifying the different client id when using durable queue or using auto-delete queue works as expect now!
MK

Staff Software Engineer, Pivotal/RabbitMQ

--
You received this message because you are subscribed to a topic in the Google Groups "rabbitmq-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rabbitmq-users/H7BPkN3YuUg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rabbitmq-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages