sending acknowledgement from consumer to producer and handle it in activemq and rabbitmq - rabbitmq

As I know ActiveMQ has a feature called AUTO Acknowledge that actually inform the broker that message has been received (not acknowledging the producer).
I want to know if it is possible to send acknowledgement from consumer to producer in ActiveMQ or RabbitMQ. then I want to handle the acknowledgment message in producer and if it wouldn't receive acknowledge then sending the message again to the consumer.

You want to perform a synchronous usecase over an asynchronous medium.
In RabbitMQ's case you can use RPC, as described here - https://www.rabbitmq.com/tutorials/tutorial-six-python.html
and
https://www.rabbitmq.com/direct-reply-to.html
Please notice that even authors advise to avoid it:
When in doubt avoid RPC. If you can, you should use an asynchronous pipeline - instead of RPC-like blocking, results are asynchronously pushed to a next computation stage.
RabbitMQ Java client provides auto-acking through com.rabbitmq.client.Channel.basicConsume.

At least for ActiveMQ - this is built in. You have to turn it on in activemq.xml
<policyEntry queue=">" advisoryForConsumed="true"/>
Simply listen the advisory topic for the queue you want to monitor consumed messages for. Then you can extract message id:s and what not to "tick off" outstanding requests.
For a complete end-to-end acknowledgement, I recommend something more custom. I.e. your producer-app should listen to some "response" queue that receives responses about the status of the produced message. I.e. if processing failed - you may want to know why etc..
Anyway, here is some code with a producer that also listens to acknowledgements from ActiveMQ.
public void run() throws Exception {
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
conn = cf.createConnection();
sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = sess.createQueue("duck");
MessageConsumer mc = sess.createConsumer(AdvisorySupport.getMessageConsumedAdvisoryTopic(dest));
mc.setMessageListener(this);
conn.start();
MessageProducer mp = sess.createProducer(sess.createQueue("duck"));
mp.send(sess.createTextMessage("quack"));
}
public void onMessage(Message msg) {
try {
String msgId = msg.getStringProperty("orignalMessageId");
System.out.println("Msg: " + msgId + " consumed");
} catch ( Exception e) {
e.printStackTrace();
}
}

Related

Where are published messages kept while RabbitMQ brokers are in a blocked state?

I noticed that when brokers are in a blocked state due to high watermark messages will not be accepted. However when they get unblocked the messages that are sent when the brokers were in a blocked state are accepted again (while the publisher is down, so they are not being republished).
Where are the messages kept? Is there a maximum amount of messages that can be kept like this, and how do I see how many? Is this behavior configurable?
I'm using a CachingConnectionFactory with a publisherConfirm in order to confirm messages are ack'd, but in this case it results in false information. The publisher confirm times out, but the broker eventually processes the message anyway.
The com.rabbitmq.client.impl.AMQChannel has a logic like this:
public void quiescingTransmit(AMQCommand c) throws IOException {
synchronized (_channelMutex) {
if (c.getMethod().hasContent()) {
while (_blockContent) {
try {
_channelMutex.wait();
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
// This is to catch a situation when the thread wakes up during
// shutdown. Currently, no command that has content is allowed
// to send anything in a closing state.
ensureIsOpen();
}
}
this._trafficListener.write(c);
c.transmit(this);
}
}
Pay attention to that while (_blockContent) {, so technically a publishing thread is blocked over here and there is no any internal queues to buffer messages until it is unblocked. We just don't go anywhere else.
See more info in official RabbitMQ docs: https://www.rabbitmq.com/connection-blocked.html
And also see Spring AMQP docs: https://docs.spring.io/spring-amqp/docs/current/reference/html/#blocked-connections-and-resource-constraints

Spring AMQP RabbitMQ RPC - Handle response exceptions

I am trying to use a RPC AMQP RabbitMQ queue to send and receive messages. The problem is that I have set a setReplyTimeout value. When that happens I get a "org.springframework.amqp.AmqpRejectAndDontRequeueException: Reply received after timeout". I have a DLQ set up on the incoming queue, but it appears that the exception is received when spring tries to return the message on its queue that is automatically created. Thus how can I handle exceptions when sending messages back to a producer? Ideally I would want any message that gets an exception while being sent to a producer sent to a DLQ.
I am using
#RabbitListener(queues = QueueConfig.QUEUE_ALL, containerFactory = "containerFactoryQueueAll")
It requires a SimpleRabbitListenerContainerFactory which does not have setQueues. Also rabbitTemplate does not have a rabbitTemplate.setReplyQueue
Thanks,
Brian
Instead of using the default built-in reply listener container with the direct reply-to pseudo queue, use a Reply Listener Container with a named queue that is configured to route undeliverable messages to a DLQ.
The RabbitTemplate is configured as the container's listener:
#Bean
public RabbitTemplate amqpTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
rabbitTemplate.setMessageConverter(msgConv());
rabbitTemplate.setReplyQueue(replyQueue());
rabbitTemplate.setReplyTimeout(60000);
rabbitTemplate.setUseDirectReplyToContainer(false);
return rabbitTemplate;
}
#Bean
public SimpleMessageListenerContainer replyListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.setQueues(replyQueue());
container.setMessageListener(amqpTemplate());
return container;
}
#Bean
public Queue replyQueue() {
return new Queue("my.reply.queue");
}
Note that the documentation needs to be updated, but you also need
rabbitTemplate.setUseDirectReplyToContainer(false);
IMPORTANT
If you have multiple instances of the client, each needs its own reply queue.

Remove message from RabbitMQ when consumed by listener. Cannot determine ReplyTo message exception

Using SpringBoot.
I have created an TopicExchange which accepts messages and directs them to two queues based on a routingKey present in the message.
Messages are sent via :
rabbitTemplate.convertAndSend('in-out-topic', 'inbound.queue.route.key', payload)
Messages are received:
#RabbitListener(queues = "inbound-queue")
def onInboundMessage(def message) {
try {
log.debug("Received inbound message: ${message.messageId} on inbound queue listener", message)
} catch (Exception ex) {
log.error("Inbound message exception: ${ex.getMessage()}")
return;
}
return message.payload
}
But when my listener (consumer) receives a message I get the following exception:
org.springframework.amqp.AmqpException: Cannot determine ReplyTo message property value: Request message does not contain reply-to property, and no default response Exchange was set.
Should I create a dummy response exchange via RabbitMQ dashboard?
Hardcode a non existent replyTo property?
Configure the existing topicExchange or Queues somehow?
I just want the message being removed from the corresponding queue when consumed by my message listener.
Your problem is in the end of method, here:
return message.payload
If you really are not going to send reply and we indeed see that by expectations via convertAndSend(), then you shouldn’t return anything from the #RabbitListener method. Otherwise, as you are experiencing, the return from such a method is treated as an attempt to send a reply.
See more info in the Reference Manual: https://docs.spring.io/spring-amqp/docs/2.0.3.RELEASE/reference/html/_reference.html#async-annotation-driven. Pay attention to the Reply Management paragraph.

RabbitMQ Request-Response pattern - consumer stops listening to queue after processing first message

I'm trying to implement RabbitMQ Request-Response pattern.
My goal is that there would be always one consumer that listens to a queue and replies to messages.
So I've set the server up by:
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume(queue: 'listensToThisQueue',
noAck: true,
consumer: consumer);
consumer.Received += (model, ea) =>
{
// Replying to client
channel.BasicPublish(exchange: '',
routingKey: routingKey,
basicProperties: props,
body: message);
// Basic ack
channel.BasicAck(deliveryTag: incomingDeliveryTag,
multiple: false);
}
Everything actually works fine:
Client sends first message
Server receive and reply
Client gets the message
The only problem is that after finshing Received method (After executing BasicAck) - Consumer stops listening to listenToQueue (I actually see 0 consumers on this queue in the UI management).
Why is that ?
This is happening because you are subscribing to the queue with noAck set to True. In this case, the consumer crashed after the first message was delivered (which is why you see 0 consumers). So you have to subscribe to the queue with noAck set to False.

Java Spring RabbitMq consumer

I am trying to create a RabbitMq consumer in Java Spring framework. Where I need to implement RabbitMq RPC model, so basically consumer shall receive some message from RabbitMq broker, process it, and send it back to the associated reply queue.
Can somebody please point me a neat sample code which implements this requirement in Spring ?
Thanks in advance.
Consider using the Spring AMQP Project.
See the documentation about async consumers. You just need to implement a POJO method and use a MessageListenerAdapter (which is inserted by default when using XML configuration) - if your POJO method returns a result, the framework will automatically send the reply to the replyTo in the inbound message, which can be a simple queue name, or exchange/routingKey.
<rabbit:listener-container connection-factory="rabbitConnectionFactory">
<rabbit:listener queues="some.queue" ref="somePojo" method="handle"/>
</rabbit:listener-container>
public class SomePojo {
public String handle(String in) {
return in.toUpperCase();
}
}
Or, you can use the annotation #RabbitListener in your POJO - again, see the documentation.
Thanks Gary, it worked for me. I used #RabbitListener annotation.
Strangely it only works when I provide queue alone, However specifying a binding of exchange, routing key and queue doesn't work. Not sure what the issue here.
Here is client code snippet in python.
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='myQueue',durable='true')
channel.basic_publish(exchange='myExchange',
routing_key='rpc_queue',
body='Hello World!')
print " [x] Sent 'Hello World!'"
connection.close()
Here is spring consumer code.
#RabbitListener(
bindings = #QueueBinding(
value = #Queue(value = "myQueue", durable = "true"),
exchange = #Exchange(value = "myExchange"),
key = "rpc_queue")
)
public void processOrder(Message message) {
String messageBody= new String(message.getBody());
System.out.println("Received : "+messageBody);
}
Not sure whats going wrong with this binding.