-
-
Notifications
You must be signed in to change notification settings - Fork 103
Description
In order to implement quarkusio/quarkus#47698, we need transactions to be handled outside of Hibernate Reactive -- or at least, that would be the most convenient solution. The idea is that:
- When Hibernate Reactive requests a connection, Quarkus returns one where a transaction is already active.
- When a Hibernate Reactive session is closed, the actual "physical" connection isn't really closed.
- Sometime after the Hibernate Reactive session is closed, Quarkus takes care of committing/rolling back the transaction and then closing the transaction.
We managed to make that work similarly to how Agroal handles it for JDBC and Hibernate ORM:
- we provide Hibernate Reactive with a custom Vert.x connection pool, which when in the Uni of a
@Transactionalmethod will always return the same connection with a transaction already active (item 1 above) - that connection is wrapped with a delegator that will ignore any call to
#closefrom Hibernate Reactive (item 2 above); - Quarkus makes sure to commit/roll back the transaction and close the connection when exiting the Uni of the
@Transactionalmethod (item 3 above).
This works fine... unless Hibernate Reactive assumes the transaction must end before the connection is closed, and forcefully rolls it back, and throws an exception. Which is precisely what happens here: https://github.com/hibernate/hibernate-reactive/pull/2929/files?diff=unified&w=1#diff-a3210bb1373db55b4feb0d8c4031314d1117c6747351f5cd267f8cc65ab8ab63R397-R408
I believe we need Hibernate Reactive to be aware that transactions are being handled externally, so that it can skip the code I linked above -- with the understanding that "someone else" is going to take care of it.
We could also skip the connection closing in that case, but I'm not sure that's wise -- Hibernate Reactive closing the connection actually gives us a hint that everything went well, so it could be useful to keep it for sanity checks.
Concretely, this could be similar to Hibernate ORM's TransactionCoordinator: there'd be a default implementation for resource-local transactions, and another one for "managed" (not quite JTA) transactions (which is more ore less what we implement in Quarkus). Thogh as far as I know, we would only need the Hibernate Reactive interface to expose one method, something like boolean isExternallyHandled, to tell Hibernate Reactive "don't rollback on connection closing".
Note: #2852 is related to this use case, and in an ideal world would be fixed at the same time, but that is not strictly necessary.