Set MDC properties only for rabbitmq events - spring-rabbit

I want to apply filters to log only for rabbit events using MDC properties.
And set trace Id && correlation id from the event header.
I already have a RequestResponseLoggingFilter which is used for setting the tenant Id.
I am not sure how to trigger this filter only for async rabbit events.

If you are using a MessageListener or #RabbitListener you can add a MessagePostProcessor to the listener container (or listener container factory, respectively) in the afterReceivePostProcessors property.
The post processor(s) are called after a message is received and before the listener is called.

Related

How can I get messageId after sending to RabbitMq?

I want some messageId kind of thing when I am sending to Rabbit Mq Queue as I will get when sending to IBM MQ using jms. I am using spring MQ amqp starter dependency with Spring Boot. Configuration is done only in application.yml (property file). I am using Rabbit template for sending.
rabbitMqTemplate.convertAndSend(EMPTY_STRING,queueName, message, messagePostProcessor);
I have tried messagePostProcessor. Any help is appreciated. I had a look into below content. But didnt understand how to implement. Does it require special configuration (connectionfactory/ container)?
https://www.rabbitmq.com/confirms.html
Unlike JMS, the rabbit client doesn't assign message ids.
However, you can configure the RabbitTemplate's MessageConverter to create an id, which you can then retrieve with a post processor.
See AbstractMessageConverter...
/**
* Flag to indicate that new messages should have unique identifiers added to their properties before sending.
* Default false.
* #param createMessageIds the flag value to set
*/
public void setCreateMessageIds(boolean createMessageIds) {
this.createMessageIds = createMessageIds;
}
For message confirmations, see the reference manual. But that is unrelated to the message id property.

Spring Cloud Bus - Custom Event Received but not handled by Event Handler

I am using Spring Cloud Bus (1.2.1.RELEASE, Camden.SR2). I have a custom event (call it CustomEvent) that I have created and registered via #RemoteApplicationEventScan as well as a custom AbstractBusEndpoint implementation to publish the event. I am able to publish events to the bus just fine.
My remote application receives the event and acknowledges (I verified this using the trace endpoint). I have verified via debugging that the CustomEvent is published via the ApplicationEventPublisher provided in BusAutoConfiguration#acceptRemote. I have a bean with an event handler in my remote application (I have this auto-configured into all of my micro-services):
#Component
public class EventListener {
#EventHandler(CustomEvent.class)
public void handleCustomEvent(CustomEvent event) {
..
}
}
Despite this, the event handler will not receive the event. I traced within the AbstractApplicationEventMulticaster class and despite my bean being created (verified via beans endpoint), the listener is not in the list of ApplicationListeners retrieved by ListenerRetriever. I do see the BusAutoConfiguration.acceptLocal listener in this list, but not my custom listener.
This event handler is also registered on the source application (the one I am accessing the bus endpoint from to initiate the event). The custom listener receives the event in this application, but not the remote application.
Essentially, both applications are configured the exact same except one is configured to send the CustomEvent using an implementation of AbstractBusEndpoint.
I am out of ideas of where else to look within the Spring code to debug this problem. If anyone has a thread they can lead me on it would be appreciated.
I've come up with the exact same problem, and debugging it revealed that ApplicationListener which handles the custom remote event not returned among candidate listeners within ApplicationEventMulticaster due to eventType was loaded by two different classloaders, one of them was devtools related classloader. Removing devtools dependency from classpath simply resolved issue for me.

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 / AQ. How to create durable subscription to multiple consumer queue. Grails

I am trying to create a durable subscription to a multiple consumer queue in oracle. Using the JMS Spring support. This is a Grails application.
My spring code is as follows:
myQueueConnectionFactory(uk.my.MyQueueConnectionFactory) {
dataSource = ref("dataSourceListener")
}
myMessageListener(uk.my.MyMessageListener)
jms.'listener-container'( 'client-id':'clientid', 'connection-factory':'myQueueConnectionFactory', 'acknowledge':'auto', 'concurrency':'1', 'destination-type': 'topic' ) {
jms.'listener'( destination:'my.queue', ref:'myMessageListener', subscription: 'subscription' )
}
I have specified the client-id and subscription values. But it appears that each time I make a connection to the queue, a new consumer is registered. Showing as something like 'TSUB_....' If I stop and start my application, then another consumer is created, and any messages added to the queue whilst the application was down are not dequeued.
Can anyone point me in the right direction to create a durable subscription. I had thought that my 'client-id' and 'subscription' values would do this for me. Do I need to specify these elsewhere?
Thanks!
Ok, I found the solution to this. Updating my destination-type to 'durableTopic' did the trick.

Resources