Good morning,
I have been meaning to reply to your question for a while now, apologies for the delay.
I will be discussing Dups-OK message transfers with local JMS transactions. This means that the JMS send and receive sessions will use local JMS transactions. These two independent local transactions will be synchronized by a JTA transaction manager. With JTA synchronized transactions, the commit for the 'put' must be acknowledged before the 'get' is acknowledged.
But first, some thoughts on using ActiveMQs message prefetch in this scenario. By default, out of the box, A-MQ will 'prefetch' 1000 messages when a recieve() call is made on a session. This presumes that the client code is going to leave the message listener up and consume all 1000 messages. If the client code just reads 1 message, for example, and then closes the session, 999 messages have to be returned to the source queue. Or, if something bad is happening, transactions may be failing and thrashing the prefetch.
I can go on with this topic at length, but just know that the Spring JMS code does not play well with transactional Camel routes and message prefetch, and I will be disabling prefetch in my example. Note that message prefetching is a performance optimization, so getting a route working without prefetch is a good thing. You may then find out that the message prefetch can increase performance, but has very undesirable side effects.
You did not mention your platform, I will be discussing a Blueprint XML file. This is very similar to a standard Camel/Spring XML file:
Blueprint Camel Route
As I am working on an OSGi platform, I have Aries installed by default as the Platform Transaction Manager, and Aries is a JTA transaction manager. If you are in Spring Boot, for example, you may need to include a starter like:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-narayana</artifactId>
</dependency>
In order to have a JTA PlatformTransactionManager (Arjuna, in this case). Do not instantiate a JmsTransactionManager and assign it as the PlatformTransactionManager.
Looking at the code, note:
<property name="brokerURL" value="tcp://10.0.0.170:61616?jms.prefetchPolicy.all=0"/>
This is disabling the message prefetching.
Note that I do not explicitly reference any transaction managers. Setting:
<property name="transacted" value="true"/>
will create a JmsTransactionManager for you.
Then the line:
<transacted id="trans"/>
will start a JTA transaction context. The two local JMS transactions will be synchronized, and you may get duplicate messages, but you will not lose messages.
Add some logging:
<logger name="org.apache.camel" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.springframework.jms.connection.JmsTransactionManager" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.apache.activemq.TransactionContext" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
Or maybe:
<logger name="com.arjuna" level="TRACE" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
If you are using Arjuna.
You should see the two commits back-to-back. This gives a very small window where a failure can result in duplicate message delivery.
I would highly recommend starting with my example as verbatim as possible. Even small deviations can have very unexpected results.
acknowledgementMode
property. Read the docs please. – Strelok