When I send reply messages to the same queue I connected to as a consumer, my consumer immediately try to consume this message again. But how to send it as reply without any further consumption?
onMessage(...){
byte[] arr = SerializationUtils.serialize(res);
//compute result message
Message resMessage = new Message(arr, composeMessageProperties(null));
message.getMessageProperties().setReplyTo("thesamequeue");
//handle result
handleResult(resMessage, message, channel);
}
Avalon,
JMS Request/Reply patterns use 2 queues.
The first queue (Request queue) is used to take requests in an process it. The second queue (Reply queue) is used to send the response to. Another listener (inside or outside your context) can then in turn read the response from your reply queue and perform logic accordingly.
Using 2 queues helps in the separation on concern. In your context, the first queue listener needs to process the request and put the response in your reply queue. That response, will then be processed by some other process/system ...
Related
#RabbitListener(queues="XYZ")
public void rabbitMsgReceiver(#Payload final UserProfile up, Message msg, Channel channel) {
}
If the message that is received is not a valid JSON of UserProfile, then ListenerExecutionFailedException occurs and the message goes to the
unack state. How can I send the message into the dead letter queue?
You can configure a dead letter queue policy in order to send unacked message to dlq instead of putting them to the original queue
https://www.rabbitmq.com/dlx.html#using-policies
example for your queue XYZ, suppose your set XYZ-dlq for it :
sudo rabbitmqctl set_policy XYZ-dlq "^XYZ$" '{"dead-letter-exchange":"", "dead-letter-routing-key":"XYZ-dlq"}' --apply-to queues
A publisher publishes messages to different destinations. My client needs to subscribe and get all those messages in those destinations one by one.Means i want to consume messages from multiple topics. Also I want the topic messages (different destinations) to be received in a button action, not by using Message Listener. Can anyone please help on this?
Part of my code is.
MessageConsumer consumer = null;
if (isDurableSubscription) {
// the subscription Name assigned to a durable subscription must be unique within a given client ID.
consumer = session.createDurableSubscriber( topic, subscriptionName );
} else {
consumer = session.createConsumer( topic );
}
log.finest("consumer = " + consumer );
consumer.setMessageListener( this );
conn.start();
}
public void onMessage(Message message) {
if ( message instanceof TextMessage ) {
try {
TextMessage txtMessage = (TextMessage) message;
String text = txtMessage.getText();
this.msg = text;
System.out.println(text);
log.finest("Message processed ...");
session.commit();
}
Also i want the topic messages (different destinations) to be
received in a button action, not by using Message Listener.
The whole point of a JMS provider is to listen to messages published by a producer and have an async communication channel in which the producer and the listener are decoupled. When you say you want to receive messages in a button action, it's equivalent of saying "I don't really care when the publisher produced the message, but I'll listen when I feel like" - which doesn't fit the use of a JMS. May be a queue where you have messages and pick one after the other based on some user action.
The publisher will not mark the message as delivered (based on how you have configured it) until the client acknowledges it and in your case (even if it were possible), it may be a long time and the message might expire. One way to achieve this, with JMS, is to have your internal data structure where you keep all your messages (after picking them up from the topic using a listener) and then process it on a button action. But you'll lose all the benefits of a JMS provider (durability, loss of messages upon client shut down, and the likes).
i am new to activemq. i read some article and doing this.please help me to solve the following task.
i produce one message to activemq from my java application and i have a consumer for that message in another java application.so i will get the message from activemq. every time this consumer(listener) looking for the message in activemq. my question is activemq can push the message to consumer(listener).
activemq only for storing the message ? it will do any push or pull operation ? activemq always need producer(produce the message) and consumer(consume the message) ?
can anyone help me
thanks
ActiveMq, WebLogic, IBM MQ, and any JMS compatible provider are destination-based messaging systems; the destination, or subject, is a queue or topic. When sending a message, producer can send the message and disconnect immediately; ActiveMq will store message on queue. When receiving, message consumer can receive sync or async, independent of sender.
Send Message
Message producer sends message to destination; it's job is done.
QueueSender queueSender = queueSession.createSender(myQueue);
queueSender.send(message);
Receive Message
Message consumer can receive message one of two ways:
Synchrounous, here you call receive() explicitly
QueueReceiver queueReceiver = queueSession.createReceiver(myQueue);
queueConnection.start();
Message m = queueReceiver.receive();
Asynchronous, here you implement callback method from MessageListener interface:
class MyQueueReceiver implements javax.jms.MessageListener {
QueueReceiver queueReceiver = queueSession.createReceiver(myQueue);
queueReceiver.setMessageListener(this);
...
public void onMessage(Message msg){
//consume message here
}
}
I have a question as regards JMS Queues.
I have implemented a jms sender/reciever using a shared queue as its the only queue avaialbe to me and the only one i can use.
The problem that i am now faced with is that i as this first come first served i cannot guarentee that the messages that i am sending from my producer will be consumed by my consumer and not the other sharing this queue and vice versa. So i am consuming the other apps messages and they are consuming mine.
Is there a way i can just listen for my messages and not consume them from the queue or is this more of a topic implementation?
Or perhaps i can explicitly set an identifier that only my consumer will pick up.
My main code:
public class AsyncReceiver implements MessageListener, ExceptionListener
{
public static void main(String[] args) throws Exception
{
//create queue factory
factory = new TibjmsQueueConnectionFactory(serverUrl);
//create queue connection
queueConn = factory.createQueueConnection(userName, password);
queueConn.setExceptionListener(this);
//create queue session
session = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
//receive message by QueueReceiver
final Queue queue = session.createQueue(queueName);
final QueueReceiver queueReceiver = session.createReceiver(queue);
queueReceiver.setMessageListener(this);
queueConn.start ();
}
You should use JMS selector. Every JMS message can contain properties that you initiate at sender's side.
Message consumer can register to JMS destination (either queue or topic) specifying selector - SQL-like statement that explains which messages does it want to consume. So you can specify your application specific property and then receive relevant messages only.
You could use message selector as shown below
queueReceiver = queueSession.createReceiver(responseQueue, "JMSCorrelationID='"
+ requestMessage.getJMSCorrelationID() +"'");
Here i am using the JMS correlation ID to identify the correct message I need.
Please note that the filter will only work on Message Header and Message properties.
It will not work on the message content.
Details on Message Header & Properties: http://docs.oracle.com/javaee/1.4/tutorial/doc/JMS4.html#wp79367
If you need to filter based on message content, you may have to use QueueSession.MANUAL_ACKNOWLEDGE mode and acknowledge messages that you want. In this case the application has to have the logic to identify messages based on content. Not the ideal design though.
I'm sending JMS requests to a Weblogic 10.3 server through a named JMS queue, and receive a reply back through a temporary queue.
Client (barebone):
//init
Destination replyQueue = session.createTemporaryQueue();
replyConsumer = session.createConsumer(replyQueue);
...
//loop
TextMessage requestMessage = session.createTextMessage();
requestMessage.setText("Some request")
requestMessage.setJMSReplyTo(replyQueue);
requestProducer.send(requestMessage);
Message msg = replyConsumer.receive(5000);
if (msg instanceof TextMessage) {
...
} else { ... }
//loop end
Server MDB (message driven bean):
public void onMessage(Message msg) {
if (msg instanceof TextMessage) {
...
TextMessage replyMessage = jmsSession.createTextMessage();
replyMessage.setText("Some response");
replyMessage.setJMSCorrelationID(msg.getJMSCorrelationID());
replyProducer.send(replyMessage);
}
}
The problem is that the very first server reply is often lost! That is, the replyConsumer.receive(5000) ends with timeout for every 4th-5th replyConsumer. When the consumer receives the first answer, then it continues to receive all the rest, so the problem is only with the first message send through the temporary queue after the temp queue has been created.
My question: Do I have to set something special for the temporary queue in order it works from the very start after being created? Or any other hint?
Further info:
When testing against my local development machine, the temp queues work without problem. The messages are getting lost only when testing against our clustered Weblogic server. However, I have switched off all cluster members but one instance.
I have verified that the server successfully replies all the requests that the client sends (by counting the sent requests and sent replies). The server replies in the order of milliseconds, even for the lost replies.
When I replace the temporary queue with a regular named queue, the problem disappears! So the problem doesn't seem (to me) to be in my code.
I've also tried to modify expiration, persistency, delay etc. of the reply message, but without success. This way I excluded the scenario that the response arrives earlier than the client begins to read the queue, and then the message immediately expires not giving the client a chance to process it.
Edit: Instead of the synchronous replyConsumer.receive(5000) I've also tried to use the asynchronous replyConsumer.setMessageListener(this). The behaviour hasn't changed, first messages are still getting lost for temp queues.
Edit: It seems that there's something wrong with the Weblogic server (or cluster) I am using. Because when I deployed the server application to another Weblogic cluster we have, everything began to work correctly! Both clusters should be configured identically - so where's a difference? It scares me that the Weblogic signals no error.
Your problem seems to be that sometimes the server is receiving the publish and discarding it before your consumer has started receiving.
The way around it is to use the asynchronous receive (replyConsumer.setMessageListener) calls instead of the blocking call you currently have (replyConsumer.receive(5000)) and to add the call to the code with the rest of your consumer code.
That way, you are already listening for replies before you send out the request.
Hope that helps.
Edit: Just read that you are using a temporary queue, so my first sentence is not correct. However as an experiment try the rest of my response to see if it changes the behaviour you are seeing