I have encountered an issue when using Reactive Transactions with PostgreSQL in Serialized Isolation mode, that when commit fails with ConcurrencyFailureException, TransactionalOperator actually tries to call rollback on the transaction.

The issue is that in ReactiveTransactionManager#rollback method, it is stated in case if commit threw an exception - you should not call the rollback method.

Currently when ReactiveTransactionManager#commit fails, the TransactionalOperator actually calls the rollbackOnException and it causes the rollback method to throw IllegalTransactionStateException with message about the transaction already being complete.

My proposal to fix this, is to wrap and exceptions that rise from commit phase in Flux/Mono.whenUsing into a special TransactionCommitException that allows us the decide weather to rollback or no, and also propagate it upstream so that client could decide to retry on such an occasion.

Comment From: pivotal-cla

@Vladislav-Zolotaryov Please sign the Contributor License Agreement!

Click here to manually synchronize the status of this Pull Request.

See the FAQ for frequently asked questions.

Comment From: pivotal-cla

@Vladislav-Zolotaryov Thank you for signing the Contributor License Agreement!

Comment From: snicoll

@mp911de can you please look at this one when you get a chance? Thanks!

Comment From: Vladislav-Zolotaryov

It seems that since I reported it almost a year ago, @EnricSala fixed this issue by unwrapping the exception produced by Flux#usingWhen in TransactionalOperatorImpl#unwrapIfResourceCleanupFailure

So even in case when commit fails with something like ConcurrencyFailureException, we should be able to properly write retry logic

Closing the issue, thank you @EnricSala

Comment From: sbrannen

Thanks for the feedback, @Vladislav-Zolotaryov.

  • Superseded by #27572