spring-projects / spring-data-geode

Spring Data support for Apache Geode
Apache License 2.0
52 stars 39 forks source link

NoTransactionException when rolling back a transaction using @Transactional #481

Closed geetrawat closed 3 years ago

geetrawat commented 3 years ago

Client App is using multiple threads to modify the same object concurrently in the same region (replicated region in this case) with transaction. When the second transaction fails, the transaction rollsback (which is correct). However, in doing so, it is throwing the following exception

org.springframework.transaction.NoTransactionException: No transaction is associated with the current thread; are multiple transaction managers present?; nested exception is java.lang.IllegalStateException: Thread does not have an active transaction

at org.springframework.data.gemfire.transaction.GemfireTransactionManager.doRollback(GemfireTransactionManager.java:235)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.doRollbackOnCommitException(AbstractPlatformTransactionManager.java:893)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:776)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:712)

at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:631)

at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385)

at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)

at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)

at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)

at <our class>

at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)

at java.util.concurrent.FutureTask.run(FutureTask.java)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

at java.lang.Thread.run(Thread.java:748)

Caused by: java.lang.IllegalStateException: Thread does not have an active transaction

at org.apache.geode.internal.cache.TXManagerImpl.rollback(TXManagerImpl.java:532)

at org.springframework.data.gemfire.transaction.GemfireTransactionManager.doRollback(GemfireTransactionManager.java:232)

... 17 more
jxblum commented 3 years ago

FYI, the Issue Reporting & Template applies here.

jxblum commented 3 years ago

Having stated the above...

BUG DESCRITION

We understand the problem is related to 2 (or more) transactions initiated from a client (i.e. GemFire/Geode ClientCache instance) in separate requests (Threads) to a (cluster of) server(s) with a REPLICATE Region, where the first transaction is successful (i.e. commits, ??), however, the 2nd transaction fails and successfully rolls back, but unfortunately results in a o.s.transaction.NoTransactionException, which seems to somehow be caused by GemFire/Geode:

Caused by: java.lang.IllegalStateException: Thread does not have an active transaction
  at org.apache.geode.internal.cache.TXManagerImpl.rollback(TXManagerImpl.java:532)

STEPS TO REPRODUCE

?

EXPECTED OUTCOME

Rollback; no Exception is thrown.

ACTUAL OUTCOME:

2nd transaction failed and successfully rolled back, however, the Spring Transaction Management Infrastructure apparently threw a NoTransactionException during the rollback operation.

This seems to have been caused by GemFire/Geode itself in the call to ...

org.apache.geode.internal.cache.TXManagerImpl.rollback(TXManagerImpl.java:532)

... from the Spring PlatformTransactionManager for Apache Geode (i.e. the SDG GemfireTransactionManager)

org.springframework.data.gemfire.transaction.GemfireTransactionManager.doRollback(GemfireTransactionManager.java:232).

jxblum commented 3 years ago

Care to share:

Include what is relevant.

??

jxblum commented 3 years ago

Re-opening to request more feedback.

jxblum commented 3 years ago

The following, recent addition of this test class to the SDG test suite proves that Spring's Transaction Management infrastructure, initiated by the Spring Framework @EnableTransactionManagement (Javadoc) and @Transactional (Javadoc) annotations in conjunction with SDG's GemfireTransactionManager (Javadoc), works correctly in the context of concurrent client transactions (initiated from different requests/Threads) against server(s) with a REPLICATE Region.

In fact, this problem should be largely Region DataPolicy independent. Meaning, this should work regardless of the (server) Region DataPolicy type (e.g. REPLICATE, PARTITION, LOCAL, etc).

There are several reasons why a NoTransactionException might be thrown, including but not limited to:

But, it is not because Spring Framework's Transaction Management combined with SDG's custom PlatformTransactionManager implementation (i.e. GemfireTransactionManager) is not properly managing (GemFire/Geode cache) transactions when Spring's Transaction Management infrastructure is enabled and used properly.

Ignoring the NoTransactionException is dangerous, particularly if you think your code has initiated, and is running in a transaction when in fact it hasn't and isn't! These type of problems turn out to be (application) configuration problems more so than infrastructure/framework problems.

spring-projects-issues commented 3 years ago

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

spring-projects-issues commented 3 years ago

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.