STOMP Messages not reaching queue - websocket

I am trying to send a message that the client inputs into the browser to a queue using STOMP and ActiveMQ. The STOMP connection is successful from the readouts I get in the console. I am not receiving errors and am using the line:
stompClient.send("/queue/testQSource", {}, JSON.stringify({ 'name': name }));
in my index.html to do so. However, when I check the ActiveMQ console after inputting into the browser, there is no addition to testQSource. Am I using the correct STOMP syntax to make this happen? Do I need to add any sources at the top of the HTML file other than the STOMP source?
The queue is instantiated here in the camel route:
<from uri="jms:queue:testQSource"/>
<to uri="securityBean"/>
<log message="Routing message from testQSource to testQDestination queue with data ${body}"/>
<to uri="jms:queue:testQDestination"/>
<to uri="activationBean"/>
<log message="message: ${body}"/>
EDIT
I am now getting a message through, but am receiving the following warning:
WARN : org.apache.camel.component.jms.JmsBinding - Cannot determine specific JmsMessage type to use from body class. Will use generic JmsMessage. Body class: hello.HelloMessage. If you want to send a POJO then your class might need to implement java.io.Serializable, or you can force a specific type by setting the jmsMessageType option on the JMS endpoint.
I believe this is because the STOMP message is of a different form than the queue and/or route are expecting. However, I am not sure how to configure my route in a way that will allow me to use my STOMP message. Any tips?

It's a bit tough to say without more information but my first guess is that the stomp client connection is being closed before the message gets a chance to be written to the socket or read by ActiveMQ. You might want to consider doing a blocking put to the queue by adding a request id to the out-bound frame and wait for the Broker to send you a response frame. This will ensure that your message is posted prior to the connection being closed.
How you perform the blocking put depends on the client you are using so you need to review the documentation to see what the correct means of doing so is. Usually there is either a sync send method or the client adds the 'receipt' header to the frame and then doing a blocking receive until you get back a RECEIPT frame with the correctly matching 'receipt-id' header.

Are you connecting on the stomp port on the ActiveMQ server ?
As seen in the config (activemq.xml) under "transportConnector"
stomp needs to connect on port 61613 on a default configuration.
Using Node.js with "stomp-client" and a default ActiveMQ server on localhost:
var my_client = new Stomp('127.0.0.1', 61613, 'admin', 'admin');

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.

What is the purpose of HandlerExtensions.ConnectHandle ConnectHandler<T>() method?

Xmldoc states:
Adds a message handler to the service bus for handling a specific type
of message
But it does not require endpoint name. How then does it work? I tried this method, but nothing happened.
Is there any possibility to add handlers dynamically, while bus is running?
By connecting a handler to the bus after it has been started, messages can be sent to the bus's address directly. This is particularly useful for things like responses to requests, which should not be published and are sent immediately back to the endpoint.
When using bus.ConnectHandler(context => {...}) to add a handler to the bus dynamically, no subscriptions or exchange bindings are created on the broker. It's only possible to receive messages which are directly sent to the endpoint.
When a message is sent from the bus, such as a request, the SourceAddress is added to the message header. If a request is sent, the ResponseAddress is also set. A fault address can also be specified if you want to use a non-dynamic endpoint to capture faults (such as a failed command that is not awaited, IE, fire and forget) so that faults can be triaged and handled appropriately by another persistent endpoint.

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

use messagestore with JSON api

I have create an API in WSO2 ESB that receives JSON messages. I have created a messagestore to store these messages in Message Broker (guaranteed delivery pattern).
Now, the message processor that must read the queue and send the message to the backend REST api, gives the error:
TID: [0] [ESB] [2014-11-21 14:28:46,752] ERROR {org.apache.synapse.message.senders.blocking.BlockingMsgSender} - Error sending Message to url : http://lnx17.redora.local:28080/MZK-DataServices/ProcessJson/cases/newCase {org.apache.synapse.message.senders.blocking.BlockingMsgSender}
org.apache.axis2.AxisFault: Payload could not be written as JSON.
The endpoint is currently defined as an address endpoint with JSON type. I have also tried a HTTP endpoint.
In Message Broker, I cannot see the message, because it is stored as an Object (?)
Any suggestions?
Before sending it to the message store, remove the REST_URL_POSTFIX using a property mediator:
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
Then the message will correctly be transferred.

Resources