Queue listener fails if queue not present Spring-Rabbit - spring-boot

We are trying to use spring-rabbit to create a message listener, in our spring boot application. But, we are getting an issue during receiving message if the queue doesn't exist, the application throws an error, which is called as passive declaration.
Channel error on connection (172.13.1.3:49352 -> 172.13.1.7:5672, vhost: '/', user: 'guest'), channel 1:
message_queue_1_1 | operation queue.declare caused a channel exception not_found: no queue 'add' in vhost '/'
What we want is to declare a queue actively, i.e. if the queue doesn't exist, it should be declared inside the mq.

To declare AMQP objects on the Broker automatically from the application, you really need to configure them as beans and also have a special AmqpAdmin bean to perform the hard declaration logic. The documentation has all the required explanation: https://docs.spring.io/spring-amqp/docs/2.0.4.RELEASE/reference/html/_reference.html#broker-configuration

Related

How to handle Connection Error in Message Driven Beans?

I have a Message Driven Bean listening to MQ Receiver Queue for incoming Messages.
My MDB is implementing MessageListener and overriding OnMessage method, where I can handle any exception related to the received messages.
All the Connection & Queue parameters are in ejb-jar.xml and weblogic-ejb-jar.xml.
So in case of any Connection failure (e.g. MQ is down, I just get Exception in the console).
How should I catch and handle these connection failure related exceptions in MDB? As I have requirement to send Email notifications to Support group in case of such Connection Failures.
I just saw some info about javax.jms.ExceptionListener, but there is no way I could use it for my setup as I don't have direct access to my connectionfactory / connection objects in case of my MDB.

What's the correct exception type to NACK a message using annotation based listener in spring-boot with amqp?

I'm using spring boot with spring-amqp and annotation based listener to consume message from a rabbitmq broker.
I've a spring component which contains a method like this:
#RabbitListener(queues = "tasks")
public void receiveMessage(#Payload Task task) {...}
I'm using the AUTO mode to acknowledge messages after successful execution of receiveMessage(...). If i detect a special error, i'm throwing AmqpRejectAndDontRequeueException to get this message into a configured dead letter queue. Now i need to nack a message only, so that the message gets requeued into the main queue of rabbitmq and another consumer has the possibility to work on that message again.
Which exception should i throw for that? I wouldn't like to use channel.basicNack(...) like described here (http://docs.spring.io/spring-integration/reference/html/amqp.html) if possible.
As long as defaultRequeueRejected is true (the default) in the container factory, throwing any exception other than AmqpRejectAndDontRequeueException will cause the message to be rejected and requeued.
The exception must not have a AmqpRejectAndDontRequeueException in its cause chain (the container traverses the causes to ensure there is no such exception).

Difference between AUTO_ACKNOWLEDGEMENT mode with and without Spring JMS

I am trying to understand how acknowledgement modes work in JMS. I was reading this source and it hugely confused me as it was contradicting what Spring's documentation says.
Sources saying one thing:
From http://www.javaworld.com/article/2074123/java-web-development/transaction-and-redelivery-in-jms.html
A message is automatically acknowledged when it successfully returns from the receive() method. If the receiver uses the MessageListener interface, the message is automatically acknowledged when it successfully returns from the onMessage() method. If a failure occurs while executing the receive() method or the onMessage() method, the message is automatically redelivered.
From http://www2.sys-con.com/itsg/virtualcd/Java/archives/0604/chappell/index.html
With AUTO_ACKNOWLEDGE mode the acknowledgment is always the last thing to happen implicitly after the onMessage() handler returns. The client receiving the messages can get finer-grained control over the delivery of guaranteed messages by specifying the CLIENT_ACKNOWLEDGE mode on the consuming session.
Spring Docs saying other things:
From http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jms/listener/AbstractMessageListenerContainer.html
The listener container offers the following message acknowledgment options:
"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default): Automatic message acknowledgment before listener execution; no redelivery in case of exception thrown.
"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after successful listener execution; no redelivery in case of exception thrown.
"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE": Lazy message acknowledgment during or after listener execution; potential redelivery in case of exception thrown.
"sessionTransacted" set to "true": Transactional acknowledgment after successful listener execution; guaranteed redelivery in case of exception thrown.
What I want to know is that why these sources are saying different things? If all are true then How do I know how/when my message will be acknowledged?
You missed out the key phrase from the abstract container javadocs...
The exact behavior might vary according to the concrete listener container and JMS provider used.
The most commonly used listener container used in Spring is the DefaultMessageListenerContainer which does exhibit that behavior - it is intended for use with transactions (either local or an external transaction manager), in order to have the ability to roll back an already acknowledged message. Its listener is invoked after the receive method, so the standard JMS auto-ack has already been applied. Any JmsTemplate operations on the thread can also use the same session - and thus can be part of the transaction.
On the other hand, the SimpleMessageListenerContainer uses a traditional MessageListener and exhibits the standard JMS behavior (the listener is called from the Consumer before receive() returns; thus exceptions will stop the ack).
I suggest you read the javadocs for those concrete implementations. From the SMLC...
This is the simplest form of a message listener container. It creates a fixed
number of JMS Sessions to invoke the listener, not allowing for dynamic
adaptation to runtime demands. Its main advantage is its low level of
complexity and the minimum requirements on the JMS provider: Not even the
ServerSessionPool facility is required.
See the AbstractMessageListenerContainer javadoc for details on acknowledge
modes and transaction options.
For a different style of MessageListener handling, through looped
MessageConsumer.receive() calls that also allow for transactional reception of
messages (registering them with XA transactions), see
DefaultMessageListenerContainer.
I will open up a JIRA issue for the docs on the abstract container because I can see that it might be misleading.

Spring Jms - Lost Context

i'm writing webapp that uses few workers. I decide to use JMS ActiveMQ to communication between them. My problem is that when i change workers configuration to java (when config was in xml i couldn't run jar) i have problem when message returns to webapp :
[org.springframework.jms.listener.DefaultMessageListenerContainer#4-3] WARN o.s.j.l.DefaultMessageListenerContainer - Execution of JMS message listener failed, and no ErrorHandler has been set.
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Earlier i had configuration like this (in xml):
<jms:listener-container>
<jms:listener destination="sample.reply" ref="sampleMessageListener" />
</jms:listener-container>
All worked correctly and then in my workers i change it to config like this:
#Bean
public static DefaultMessageListenerContainer configureListener() {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setDestinationName("xxxxx.xxxxx");
container.setMessageListener(context.getBean("someBean"));
container
.setConnectionFactory(context.getBean(ConnectionFactory.class));
container.setConcurrency("5-10");
return container;
}
This also works but when i send message back to webapp i see problem with lost context.

How to stop exception propagation if jms broker is down when sending a message with spring integration?

I configured spring xml based interceptor, which sends a jms message to activemq queue on each invokation of some transactional method after it is commited. It's happening with the following xml code.
<jms:outbound-channel-adapter channel="filteredStakesChannel" destination="stakesQueue" delivery-persistent="true" explicit-qos-enabled="true" />
But if the activemq server is down i get connection refused exception, which is propagated and i don't want this to happen even if the jms delivery fails. Is this possible?
Should i use some error-channel?
The simplest solution is to make fileredStakesChannel an Executor channel and the send will run on a different thread.
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#executor-channel
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#channel-configuration-executorchannel
Use the <task/> namespace to define an executor to use.

Resources