In our application we have following happy path flow:
- Gateway-> jmstemplate.send msg(with replyTo=Gateway-Node-Specific_queue) to BE GenericQueue and wait for response via Listener (Gateway-Node-Specific_queue)
- BE -> received msg via Listener (BE GenericQueue)
- BE build Out-API request from msg and jmstemplate.send msg(with replyTo=BE-Node-Specific_queue) to Gateway GenericQueue and wait for response via Listener (BE-Node-Specific_queue)
- Gateway -> received msg via Listener (Gateway GenericQueue), forwards the Http request to out APIs, upon receiving Http response jmstemplate.send msg to BE-Node-Specific_queue
- BE -> upon receiving the msg from BE-Node-Specific_queue, jmstemplate.send response msg to Gateway-Node-Specific_queue
Node-Specific_queue msgs are correlated with a UUID-CorrelationId
Now it is observed that when at step #2 and #3 BE tries to call jmstTemplate.send to Gateway from inside JmsListener method, Gateway does not receive the msg until control comes out of BE listener method. We dont use any kind of transactions.
I'm trying to understand why it is not working, what has worked so far is if jmsTemplate.send is executed in a separate thread inside the JmsListener method. Why executing this code JMSListener with thread has not worked? Is there any external configuration which could help without any code change?
When on the same thread, a JMS broker will not perform the send() until the message receive() from the listener is acknowledged. This is why you do not see your message until the listener method exists. This context is thread local, so if you start a new thread you will not see this behavior.
I suspect that you are using the same JMS connection factory for both receive and listen. If you use a different JMS connection factory for these operations, you may not see this behavior.
Following on from your question...
This is a long question and answer. The javadoc for AbstractMessageListenerContainer could be helpful.
Originally, when a user would use the DefaultMessageListenerContainer, the default behavior was to immediately ACK the incoming message. The user had to know that if an exception occurred, that the incoming message had already been acknowledged and that message loss could occur. You had to set up some form of transaction in order to delay sending the ACK for the incoming message until your processing had completed.
Using a JmsTransactionManager for this purpose was common. Note that the
JmsTransactionManagercan only manage a single JMS connection factory. This is why using a different connection factory can work around transactions with theJmsTransactionManager.With the modern templates, this is set up for you. You are actually using transactions, and the inbound message is ACKed when the listener exists (unless you extend the transactional context with other transactional methods).