How to configure rabbitmq reply queues using spring-amqp? - rabbitmq

We are trying to make asynchronous call in RabbitMQ using Spring AMQP, could any one please tell me how to configure replyqueue, correlationId, (properties) using spring amqp?
String corrId = java.util.UUID.randomUUID().toString();
BasicProperties props = new BasicProperties
.Builder()
.correlationId(corrId)
.replyTo(replyQueueName)
.build();
channel.basicPublish("", requestQueueName, props, message.getBytes());

I assume you need to use RabbitTemplate:
rabbitTemplate.convertAndSend(requestQueueName, myObj, new MessagePostProcessor() {
Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setReplyTo(replyQueueName);
return message;
}
}, new CorrelationData(corrId));
HTH

Related

RabbitMQ Camel Consumer - Consume a single message

I have a scenario where I want to "pull" messages of a RabbitMQ queue/topic and process them one at a time.
Specifically if there are already messages sitting on the queue when the consumer starts up.
I have tried the following with no success (meaning, each of these options reads the queue until it is either empty or until another thread closes the context).
1.Stopping route immediately it is first processed
final CamelContext context = new DefaultCamelContext();
try {
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
RouteDefinition route = from("rabbitmq:harley?queue=IN&declare=false&autoDelete=false&hostname=localhost&portNumber=5672");
route.process(new Processor() {
Thread stopThread;
#Override
public void process(final Exchange exchange) throws Exception {
String name = exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class);
String body = exchange.getIn().getBody(String.class);
// Doo some stuff
routeComplete[0] = true;
if (stopThread == null) {
stopThread = new Thread() {
#Override
public void run() {
try {
((DefaultCamelContext)exchange.getContext()).stopRoute("RabbitRoute");
} catch (Exception e) {}
}
};
}
stopThread.start();
}
});
}
});
context.start();
while(!routeComplete[0].booleanValue())
Thread.sleep(100);
context.stop();
}
Similar to 1 but using a latch rather than a while loop and sleep.
Using a PollingConsumer
final CamelContext context = new DefaultCamelContext();
context.start();
Endpoint re = context.getEndpoint(srcRoute);
re.start();
try {
PollingConsumer consumer = re.createPollingConsumer();
consumer.start();
Exchange exchange = consumer.receive();
String bb = exchange.getIn().getBody(String.class);
consumer.stop();
} catch(Exception e){
String mm = e.getMessage();
}
Using a ConsumerTemplate() - code similar to above.
I have also tried enabling preFetch and setting the max number of exchanges to 1.
None of these appear to work, if there are 3 messages on the queue, all are read before I am able to stop the route.
If I were to use the standard RabbitMQ Java API I would use a basicGet() call which lets me read a single message, but for other reasons I would prefer to use a Camel consumer.
Has anyone successfully been able to process a single message on a queue that holds multiple messages using a Camel RabbitMQ Consumer?
Thanks.
This is not the primary intention of the component as its for continued received. But I have created a ticket to look into supporting a basicGet (single receive). There is a new spring based rabbitmq component coming in 3.8 onwards so its going to be implemeneted there (first): https://issues.apache.org/jira/browse/CAMEL-16048

Rabbit mQ messages moving from ready queue to Unack queue

I have a separate publisher and consumer.I start publisher and publish messages.Now i start consumer and problem is that the messages move from ready queue to unack queue marking the messages as redelivered which i want to avoid.So what i want is it should be marked as redelivered only if i send ack and not on consumer restart or start
Configuration :
#Bean
public org.springframework.amqp.rabbit.connection.Connection mqConnection() {
CloudFactory cloudFactory = new CloudFactory();
Cloud cloud = cloudFactory.getCloud();
return cloud.getServiceConnector("mqservicename", ConnectionFactory.class,
null).createConnection();
}
#Bean
public StatefulRetryOperationsInterceptor interceptor() {
return RetryInterceptorBuilder.stateful().retryOperations(retryTemplate()).recoverer(new RejectAndDontRequeueRecoverer())
.build();
}
#Bean
public SimpleMessageListenerContainer listenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setMessageListener(new MessageListenerAdapter());
container.setAdviceChain(new Advice[] {
interceptor()
});
return container;
}
#Bean
public RetryTemplate retryTemplate(){
Map map=new HashMap<Class<? extends Throwable>, Boolean>();
map.put(CustomException.class, true);
RetryTemplate retryTemplate=new RetryTemplate();
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(3,map));
return retryTemplate;
}
If you are using Spring AMQP, you need to show your configuration when asking questions like this.
If you set the ack mode to MANUAL, you are responsible for the acks. Read the documentation. For AUTO ackmode, the container will ack the message when the listener returns normally.

How can I know where does a message in rabbitMQ send from?

When we using rabbitMQ topic exchange, We can send a message at everywhere. And our project is very large, when I receive a message, and we found there is a problem in the message and we want to modify the message at where it was sent. But it is hardly be found where the message was sent.
Is there a method or a command tool in rabbitMQ to find out where that message sent from.
there are a few information that you can take using the envelop, as exchange, delivery_tag, routing_key :
Consumer consumer_a = new DefaultConsumer(channel) {
#Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
long delivery_tag = envelope.getDeliveryTag();
String exchange_from = envelope.getExchange();
String routing_key = envelope.getRoutingKey();
}
};
if you need more info you can use the headers to add custom information as:
var properties = new BasicProperties();
properties.Headers = new Dictionary<string, object>();
properties.Headers.Add("mysender_user", "my_server");
properties.Headers.Add("my_custom_info", "my_info");
channel.BasicPublish(ExchangeName, "", properties, message);

Identify ActiveMQ asyncrhonous message failures?

I have ActiveMQ persistent queue and due to performance i'm publishing to producer using async mode.
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
factory.setUseAsyncSend(true);
PooledConnectionFactory connectionFactory = new PooledConnectionFactory(factory);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProduer producer = session.createProducer(destination);
Queue queue = session.createQueue(qName);
producer.send(queue, message);
Is there a way to register handler to get the error/success of producer.send() method ?
Seems like jms 1.1 specification does not allow to register call back in send method and jms 2.0 allows it ( http://www.oracle.com/technetwork/articles/java/jms2messaging-1954190.html ). Since ActiveMq based on jms 1.1 there's no standard way to register callback. However ActvieMQ javax.jms.MessageProducer implementation org.apache.activemq.ActiveMQMessageProducer allows to register callback and I used that to create my solution ( but unfortunately i had to abandon PooledConnectionFactory because there was no way to get org.apache.activemq.ActiveMQMessageProducer from PooledConnectionFactory approach.
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
factory.setUseAsyncSend(true);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProduer producer = session.createProducer(destination);
Queue queue = session.createQueue(qName);
((ActiveMQMessageProducer)producer).send(queue, message, new AsyncCallback() {
#Override
public void onSuccess() {
}
#Override
public void onException(JMSException exception) {
}
};);

How to receive messages for a correlationid from RabbitMQ using Spring AMQP

I went through the API of RabbitTemplate. It provides only receive method which gets the message from queue. However there is no way to get a message with a particular correlation id. Can you please help me understand what I am missing here.
Currently, I am using JMS API's from ActiveMQ to receive messages using the following code which createConsumer with message selector. Looking to do the same with Spring AMQP with RabbitMQ:
private ObjectMessage receiveMessage(final String readQueue, final UUID correlationId, final boolean isBroadcastMessage, final int readTimeout) throws JMSException
{
final ActiveMQConnectionFactory connectionFactory = this.findConnectionFactory(readQueue);
Connection connection = null;
Session session = null;
MessageConsumer consumer = null;
ObjectMessage responseMessage = null;
try
{
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(readQueue);
consumer = session.createConsumer(destination, "correlationId = '" + correlationId + "'");
final Message message = consumer.receive(readTimeout);
}
finally
{
if (consumer != null)
{
consumer.close();
}
if (session != null)
{
session.close();
}
if (connection != null)
{
connection.close();
}
}
return responseMessage;
}
You are using a messageSelector string in JMS; RabbitMQ/AMQP does not have an equivalant.
Instead, each consumer gets its own queue and you use a direct or topic exchange in the broker to do the routing. I suggest you take a look at the tutorials on the rabbitmq web site and topics.
If you are using the correlationId for request/reply processing, consider using the inbuilt sendAndReceive or convertSendAndReceive methods in the template. See the reference documentation for more information.