Spring Boot/RabbitMQ avoid unack msg - java

#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

Related

spring rabbit reply to the same queue

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 ...

Subscribe to multiple topic destination in ActiveMQ Messaging

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).

How to not acknowledge only one message with Spring-JMS?

There is a class 'MyConsumer' which receives messages from a queue, and processes them. There are two requirements:
If there is a message contains invalid content, MyConsumer should not acknowledge it, but can process later messages
The unconsumed message will be deliver again when MyConsumer restarts
I tried with spring-jms, with the listener-container supports, but can't find a solution fits the first requirement.
My code:
<amq:queue id="destination" physicalName="org.springbyexample.jms.test"/>
<amq:connectionFactory id="jmsFactory" brokerURL="tcp://localhost:11111"/>
<bean id="jmsConsumerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
p:targetConnectionFactory-ref="jmsFactory"/>
<bean id="jmsConsumerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="jmsConsumerConnectionFactory"
p:defaultDestination-ref="destination"/>
<bean id="jmsMessageListener" class="test.MyConsumer"/>
<bean id="errorHandler" class="test.MyErrorHandler"/>
<jms:listener-container container-type="default"
connection-factory="jmsConsumerConnectionFactory"
error-handler="errorHandler"
acknowledge="client">
<jms:listener destination="org.springbyexample.jms.test" ref="jmsMessageListener"/>
</jms:listener-container>
Class MyConsumer:
#Override
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("!!!!!!!!! get message: " + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
if (theNumberOfMessageIs(3)) {
throw new RuntimeException("something is wrong");
}
}
You may notice that the acknowledge in listener-container is client, actually it has 3 values:
auto (default)
client
transacted
I tried all of them, but none fits my requirement. My test scenario:
producer put 3 messages to queue
start a thread to monitor the message count in queue, when the count changes, print it
start consumer, it will receive messages from queue, and processes them
wait a while, put another 3 messages to queue
For auto:
MyConsumer will acknowledge after receiving each message, no matter throwing exception or not
For client:
MyConsumer will acknowledge only if no exception thrown in onMessage. For the 3rd message, it throws exception, there will be a message in the queue unconsummed. But when it get the 4th message and doesn't throw exception, the 3rd message in queue will be disapeared
For transacted:
If exception thrown in MyConsumer, the message will not be acknowledged and be re-delivered several times. After that, the message is disappeared from queue
But none of them fit the requirement 1.
I wonder: if I need to look for other solution than Spring-jms, or my usage is not correct?
auto The DefaultMessageListenerContainer is really designed for transactions - with auto, as you have found, the message is always acknowledged. You can use a SimpleMessagseListenerContainer which will work as you desire, but it has other limitations; see the JavaDocs.
client That's just the way JMS works when you ack #4, #3 is automatically acked too - see the Message JavaDocs. Client mode is used to reduce ack traffic (by, say, acking every 10 messages).
transacted That's a function of the broker, you can configure AMQ to send the bad message to a Dead Letter Queue after some number of retries.
You would need some process to move messages from the DLQ back to the main queue for later retry (perhaps during initialization on restart).
Using WMQ you can achieve the requirement using BackOut feature using BOTHRESH and BOQNAME QUEUE configuration parameters, where BOTHRESH define how many times you will try consume the message and after that parameter BOQNAME define the name of QUEUE that your message you be redelivery. In this case you can use a DLQ QUEUE where you can move messages to main QUEUE after some time or use you main QUEUE as DLQ QUEUE that enable message rotate in you consumer.
Hope that helps.

How to push message from Activemq

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
}
}

JmsCorrelationId for async messaging send

Are there any set norms for what a JMSCorrId should be set to. My application is simply sending a message async to a queue and it doesn't care about waiting for any acknowledgement.
When the JMS client receives the reply message, it can match the JMSCorrelationID of the new message with the corresponding JMSMessageID of the message it sent, so that it knows which message received a reply.
The JMSCorrelationID can be any value, not just a JMSMessageID.
For example you can use JMSCorrelationID to identify the sender.
If you decide to use your own ID, be aware that you should not start an application-specific JMSCorrelationID with ID:. That prefix is reserved for IDs generated by JMS providers.
Typically implementation:
public void onMessage(Message message){
try {
TextMessage textMessage = (TextMessage)message;
Queue replyQueue = (Queue)textMessage.getJMSReplyTo();
Message replyMessage = session.createMessage();
replyMessage.setJMSCorrelationID(message.getJMSMessageID());
sender.send(replyQueue, replyMessage);
} catch (JMSException jmse){jmse.printStackTrace();}
}

Categories

Resources