atomikos / transactions-essentials

Development repository for next major release of
https://www.atomikos.com/Main/TransactionsEssentials
Other
462 stars 139 forks source link

Interposed Synchronizations are not executed in case of a rollback #185

Closed klaasdellschaft closed 6 months ago

klaasdellschaft commented 1 year ago

Describe the bug Since 6.0.0, Atomikos supports the TransactionSynchronizationRegistry for registering interposed synchronizations. I need this functionality because I have a Synchronization whose afterCommit() functionality needs to be executed before executing the afterCommit() of other "regular" synchronizations.

In case of committing a transaction, the interposed synchronizations work as expected, i.e. their afterCommit() is executed before any other "normal" synchronizations. However, in case of a rollback, the interposed synchronizations registered with the transaction do not get executed. Only the "normal" synchronizations are getting notified about the rollback of the transaction.

To Reproduce Steps to reproduce the behavior:

  1. What I were doing: Registering an interposed synchronization with the TransactionSynchronizationRegistry.
  2. What happened: The interposed synchronization only gets executed / notified upon a commit attempt.
  3. What I expected to happen: I expect that interposed synchronizations are also executed in case of any kind of rollback, i.e. independent of whether the transaction got rolled back during a commit or whether it was rolled back without a prior commit attempt.
  4. What TransactionsEssentials version you are using: transactions-jta:6.0.0

Additional context I think this behavior may be influenced on how the rollback got triggered. If the application first tries to do a commit of a transaction, and then gets a rollback, e.g. due to a constraint violation in the database, then the interposed synchronizations may also be executed. However, if the transaction was rolled back by the application itself, e.g. due to an exception being thrown in the application code, then the interposed synchronizations are not executed.

The reason is most likely available in how the interposed synchronizations are handled in TransactionImp. It seems to me, that only in case of a commit, the interposed synchronizations are registered with the compositeTransaction: https://github.com/atomikos/transactions-essentials/blob/master/public/transactions-jta/src/main/java/com/atomikos/icatch/jta/TransactionImp.java#L176

However, if a rollback is triggered without a prior commit attempt, no registration of the interposed synchronizations with the compositeTransaction is taking place: https://github.com/atomikos/transactions-essentials/blob/master/public/transactions-jta/src/main/java/com/atomikos/icatch/jta/TransactionImp.java#L203

GuyPardon commented 1 year ago

Looks like you have a point. Scheduled for the 6.0.1 release.

klaasdellschaft commented 1 year ago

Hi @GuyPardon thanks for feedback and the quick fix in 6.0.1.

When I was looking at the code (and wondering how I would implement the fix), I was asking myself in how far concurrent threads (and thus potentially multiple calls to commit / rollback) need to be considered? At the moment, the interposed synchronizations may be added multiple times to the compositeTransaction if the commit would be called several times.

GuyPardon commented 1 year ago

Do you have a use case for one JTA transaction shared by different threads?

klaasdellschaft commented 1 year ago

No. It is just a question out of curiosity.

GuyPardon commented 6 months ago

Implemented and tested for 6.0.1