23 Oct 2013

"javax.jms.TransactionInProgressException: Cannot rollback() inside an XASession"

The following problem has come up repeatedly among ActiveMQ/Camel/Karaf users so I want to capture it here in this post.

Most of the time the use case is a Camel route deployed into Karaf consuming messages using XA transaction from an ActiveMQ broker (using Aries as the TX manager). A possible example route can be found in the Camel-WMQ-AMQ-XA-TX demo on my fuse-demos github repoository. Deploying this demo to Fuse ESB Enterprise 7.1 will immediately reproduce the problem.

When Camel tries to commit the XA transaction it raises the following warning:
14:58:37,063 | WARN  | Consumer[ESB_IN] | PooledSession | 122 - org.apache.activemq.activemq-pool - 5.7.0.fuse-71-047 | 
Caught exception trying rollback() when putting session back into the pool, will invalidate. 
javax.jms.TransactionInProgressException: Cannot rollback() inside an XASession
    at org.apache.activemq.ActiveMQXASession.rollback(ActiveMQXASession.java:76)[125:org.apache.activemq.activemq-core:5.7.0.fuse-71-047]
    at org.apache.activemq.pool.PooledSession.close(PooledSession.java:120)[122:org.apache.activemq.activemq-pool:5.7.0.fuse-71-047]
    at org.springframework.jms.connection.JmsResourceHolder.closeAll(JmsResourceHolder.java:193)
    at org.springframework.jms.connection.ConnectionFactoryUtils$JmsResourceSynchronization.releaseResource(ConnectionFactoryUtils.java:412)
    at org.springframework.jms.connection.ConnectionFactoryUtils$JmsResourceSynchronization.releaseResource(ConnectionFactoryUtils.java:1)
    at org.springframework.transaction.support.ResourceHolderSynchronization.beforeCompletion(ResourceHolderSynchronization.java:72)
    at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCompletion(TransactionSynchronizationUtils.java:106)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCompletion(AbstractPlatformTransactionManager.java:940)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:738)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.apache.aries.transaction.GeronimoPlatformTransactionManager.commit(GeronimoPlatformTransactionManager.java:76)
    at sun.reflect.GeneratedMethodAccessor33.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[:1.6.0_65]
    at java.lang.reflect.Method.invoke(Method.java:597)[:1.6.0_65]
    at org.apache.aries.proxy.impl.ProxyHandler$1.invoke(ProxyHandler.java:54)[13:org.apache.aries.proxy.impl:1.0.0]
    at org.apache.aries.proxy.impl.ProxyHandler.invoke(ProxyHandler.java:119)[13:org.apache.aries.proxy.impl:1.0.0]
    at com.sun.proxy.$Proxy74.commit(Unknown Source)[148:org.springframework.transaction:3.0.7.RELEASE]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257)[153:org.springframework.jms:3.0.7.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1058)[153:org.springframework.jms:3.0.7.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1050)[153:org.springframework.jms:3.0.7.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947)[153:org.springframework.jms:3.0.7.RELEASE]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)[:1.6.0_65]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)[:1.6.0_65]
    at java.lang.Thread.run(Thread.java:695)[:1.6.0_65]


This problem is caused by a bug in activemq-pool of version 5.7.0 (and most likely earlier versions). It is raised under ENTMQ-441.

Version 5.8.0 of activemq-pool has this bug fixed already. So anyone running into this problem, check if you're using ActiveMQ 5.7.0 on the client side. If so, upgrade to ActiveMQ 5.8.0 on the client. JBoss Fuse 6.0 uses ActiveMQ 5.8.0.

If you are running on Fuse ESB Enterprise 7.x and you cannot upgrade to JBoss Fuse 6.0, then a possible solution is to replace the activemq-pool/5.7.0 bundle with version 5.8.0. You can follow these steps:

  • osgi:stop <bundleid of your Camel route doing XA>

  • osgi:list -l -t 0 | grep activemq-pool.
    Take note of the bundle id

  • osgi:uninstall <bundleid>

  • As the 5.8.0 version of activemq-pool is not an OSGi bundle, we need to wrap it accordingly
      osgi:install 'wrap:mvn:org.apache.activemq/activemq-pool/5.8.0 \
    $Bundle-SymbolicName=org.apache.activemq.activemq-pool&Bundle-Version=5.8.0& \
    Export-Package=org.apache.activemq.pool;version=5.8.0'

  • osgi:refresh <bundleid of your Camel route doing XA>

  • osgi:start <bundleid of your Camel route doing XA>


This should rewire your Camel bundle to use the new activemq-pool jar. If you still see the exception, run a packages:imports and verify if it pulls in activemq-pool from the new jar file. It may be that instead it now pulls in from activemq-spring.
In this case I suggest to change the maven-bundle-plugin configuration and explicitly require activemq-pool to be of version 5.8.0 or higher, using e.g. the following configuration

  org.apache.felix
  maven-bundle-plugin
  true
  
    
      ...
      *, org.apache.activemq.pool;version="[5.8.0,6)" 
    
  



You will need to rebuild and redeploy the Camel route.