Calling dispatch in subscribe in Autobahn - autobahn

I am using Autobahn and I have an implementation-specific question.
I am trying to figure out how to send a notice to all connected clients (including the newly subscribed client) upon a client subscribing to a topic. Here's the code (edited down for clarity):
#exportSub("", True)
def subscribe(self, topicUriPrefix, topicUriSuffix):
topic_uri = "%s%s" % (topicUriPrefix, topicUriSuffix)
self.client.dispatch(topic_uri, {"msg":"WTF"})
return True
Yet, I'm not seeing the newly subscribed message receive this dispatch. The dispatch call is returning None.
What's happening here?

I figured this out. A client must first be subscribed to a topic before receiving a message sent via dispatch(). This means that the dispatch() cannot be called inside subscribe if one expect the subscribing client to receive the message. I worked around this problem by building a simple message queue and calling dispatch on the protocol instance for any queued messages.

Related

setting ack to client results in duplicate message delivery stomp

I have a stomp application and I set the ack mode to client during subscription from front-end. During the subscription the same client during a session would connect to the same queue in the message broker ActiveMQ Artemis because a session id is used for queue.But a different id is passed in the header every time the user reloads the page.
The subscription code is shown below.
consumer.subscribe(
'/queue.'+ rscSessionId,
function (response) {
console.log("resposne");
},
{
"subscription-type": "ANYCAST",
ack: "client",
id: generateId(),
}
);
Once I send message from client it gets send to frontend with following headers.
MESSAGE
subscription:1234
message-id:1543449
destination:/queue.sessionid
expires:1653914606725
redelivered:false
priority:4
persistent:true
timestamp:1653912806717
destination-type:ANYCAST
__AMQ_CID:30e64793-dd9b-11ec-8843-c238460c3152
_type:ResponseData
content-length:300
and afterwards on every reload.
MESSAGE
subscription:1235
message-id:1543449
destination:/queue.sessionid
expires:1653914606725
redelivered:true
priority:4
persistent:true
timestamp:1653912806717
destination-type:ANYCAST
__AMQ_CID:30e64793-dd9b-11ec-8843-c238460c3152
_type:ResponseData
content-length:300
You can see that redelivered is set to true after first delivery and after that every response has redelivered to false. the subscription value keeps getting changed though because of the id passed in header.
How can I make it deliver only once but with guarantee?
Are you actually acknowledging the message once you receive it? If you don't acknowledge the message then once the client closes the connection and subscribes again it will receive the same message again. The different value you're seeing for the subscription header indicates this is what is happening.
To be clear, if you're using the client acknowledgement mode then once you receive the MESSAGE frame you need to send a corresponding ACK frame in order to acknowledge the message. Your client should have a way to do this since it is a standard part of the STOMP specification.
I guess that Artemis is configured with publisher/subscriber messaging style. In this case, every new consumer/receiver/client will get the messages aka you write/read from a topic.
Changing to a point-to-point message style would fix the issue (would only be read once) aka a queue.
This is usually decided by the setup but I recall that ActiveMQ allowed producer to create those on the fly.
If you do need a topic, then you will have to handle the IDs on the client side.

In a group chat, should the new message event (websocket) be sent by the client or the API?

I have a doubt, in a group chat system that has a database with a rest API, who should issue the event of a new message?
The client or the endpoint to create the new message?
For example: X user sends a message to group Y, then uses the api endpoint api.com/message-create and that endpoint emits the message-create event through websocket
Example 2: X user sends a message to group Y, then uses the api api.com/message-create endpoint and the endpoint does not emit the message-create event, but was emitted when the user pressed the send message button
I still don't quite understand if it would occupy more websocket channels to achieve that, if a global one is enough, etc.
The server should be responsible for communication logic. So your first example is better.
But: why do you use two communication channels for sending an creating messages?
If you use websocket, you don't need create a message from a client by using additional rest endpoint.
This approach is prone to errors. For example if the client will loose network connection after sending message through websocket and before executing call to the REST endpoint?
The message will not be stored in a database.
Your flow should looks as follows:
User clicks the send button.
Message is send through the websocket.
Message is stored in the database asynchronously (you can do it directly from communication server, or use rest endpoint)
Emit "new message" event to the group.

Alternatives of MQJExplorer tool for capturing request and sending response

I have an application which uses IBM MQ to send out the request in a queue manager to a particular system B.
The response corresponding to that request is then received back from system B by the application in a sync call and then further business processing happens.
Since we are working on the offshore region, we do not actually send out the request to system B but rather capture it ourselves using the MQJExplorer tool and send back the response, which kind of simulates the prod. behaviour.
The problem here is, or i would say, the overhead is that we have to manually open the mqjexplorer tool, check the request, take a particular attribute from the request(lets say ID), and send back ID+1 so that the application recognizes the response is for ID-1 request.
I would like to know if this particular thing can be automated, with some other tool, where i can define like whenever any such kind of request is received in for eg: MQ001 queue manager and its REQ queue, just extract the ID attribute, do a ID+1 and send back the response in RESP queue of same qm.
There are a pair of IBM supplied samples that come with IBM MQ:-
amqsreq0.c - Sample C program that puts request messages to a message queue and shows the replies (example using REPLY queue)
amqsecha.c - Sample C program - echo messages to reply to queue
They are supplied to allow you to try out a request/reply application.
You already have the equivalent app to do the job that amqsreq0.c does, and you could adapt amqsecha.c to extract your ID attribute, increment it, and then the sample already has the code to send the reply back.
It can be automated by running as a triggered application too.
If 'C' language is not your thing and prefer Java then have a read of a blog posting I did in 2017. It is a complete request/reply scenario with 2 applications: BEServer01.java and RQClient01.java
You can modify BEServer01.java to your liking (and remove the SQL code). BEServer01.java contains all of the code for getting a request message and sending a reply message. Simply replace the variable 'replyText' contents with the reply message that you want.
If you are not a programmer then there is another option but it does not modify the message contents. MQ Visual Edit has a component called: SIM Server. Its purpose is to simulate a server-side component. You configure what 'request' queue to get the messages from and what the reply message text will be. When a messages lands on the request queue, the SIM Server will retrieve it and send the reply message to the queue & queue manager specified in the MQMD's ReplyToQueueName and ReplyToQueueManagerName fields.

Send messages to the temporary queue with MassTransit

I have the following scenario, where i can not respond directly to the request of a MassTransit RequestClient
Request Service 1 implementing a RequestClient and calling GetResponse
Another service 2 have the consumer of the request that just save the request information (messageId, requestId ...) to some storage and not send a response back.
Based on an API call in service 2, we can find the saved request information and send back the response to the RequestClient. I could achive this by sending the response to the temporaty queue of the RequestClient bus but the message ends up in the skipped queue of the temporary queue and GetResponse never gets the message.
How can i make the message arrives to the main temporary queue, and that the GetResponse consumer find it.
If anyone has a similar scenario. We achived this by implementing an event waiter mechanism in the consumer. When the external API call is made in service 2, an internal event is fired then consumer who is waiting for it through ResetEvent continue by gathering the response and send it back through out of the box RespondAsync.

Multiple user sessions not receiving subscription message - spring stomp websocket

I am using Spring stomp websocket framework to send subscription messages to the clients. We are using ActiveMQ as the message broker
and is using a stomp javascript client. Spring 4.1.5 and In this architecture, the messages are sent using
simplemessagingTemplate.convertAndSendToUser(user, "/queue/msg", serverMsg, map);
In order to ensure that only the right user receive their message, I am also making use of a QueueSubscriptionInterceptor that implements ChannelInterceptor.
The messages are delivered to the destination correctly. The messages are received using the JS client like this.
stompClient.subscribe('/user/guest/queue/msg', function(greeting){
x = JSON.parse(greeting.body);
...
}
So far so good. However, when there are multiple user session, only one session receives the message. For (e.g), if two "guest" users
are logged in, I would like all the two "guest" users to receive the message. This doesnt seem to be happening. Looking into the logs,
I see that the message seems to be sent..
2015-04-11 14:39:40 DEBUG StompBrokerRelayMessageHandler:738 - Forwarding SEND /queue/msg-user1 session=_system_ application/json;charset=UTF-8 payload={"my message to you...)
2015-04-11 14:39:40 DEBUG StompBrokerRelayMessageHandler:738 - Forwarding SEND /queue/msg-user0 session=_system_ application/json;charset=UTF-8 payload={"my message to you...)
I see only one client receiving the message and not the other. Reading the Spring documentation, I understand that this is the default behaviour.
Can someone tell me what I am doing wrong.
Thanks.
You should use the semantic of topics instead of queues.
A queue allows the message to be consumed once, but a topic will allow it to be consumed once per subscriber. So something like /topic/user/guest/msg probably would do it.
Set the ack header in the connect frame. What this will do is that the server will continue to send you the same message until you send back an ack frame. Which I am doing below by calling greeting.ack() as soon as receive the message. Setting it to 'client-individual' will mean that the server has to receive ack from all sessions of the particular client or it will keep re sending the same msg on every CONNECT.
Hope this helps!!
Use below code for reference.
function connect() {
var socket = new SockJS('/powerme-notification-websocket');
stompClient = Stomp.over(socket);
stompClient.connect(
{client_id:'testClient'}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/topic/releaseLock', function (greeting) {
stompClient.subscribe('/queue/releaseLock-testClient', function (greeting) {
console.log(greeting);
showGreeting(greeting.body);
greeting.ack();
},{durable:true,
'auto-delete':false,
ack:'client-individual',
id:'testClient'});
});
}
References:
https://stomp.github.io/stomp-specification-1.2.html#ACK

Resources