So Gunnar, your workaround is fine today but will pose problems in the future if we decide
that onRollback for ErrorHandler needs access to the session somehow to be able to
compensate and undo the already executed operations:
- a closed session will do us no good
- there is a harder problem that Scott mentions below related to tx reaping in a different
thread
Let’s try and find a solution for the first problem.
@Scott, I think what happens is the following:
- Hibernate registers a Sync when the EM is created (for the flush() callbacks and a few
other things)
- Synchronization attached to the Hibernate Transaction objects are piggybacking on that
initial Sync attachement
- Wildfly attach a “close session” Sync once it has the instance of EntityManager
- according to your rules, the close session afterTransaction Sync is called before the
one Hibernate put
- that explains why Gunnar finds an already closed Tx.
But since Gunnar attaches its Sync when the Hibernate TransactionCoordinator creates the
Hibernate transaction, which is when the EM is created, I can’t explain why the workaround
works.
Emmanuel
On 10 Mar 2015, at 14:39, Scott Marlow <smarlow(a)redhat.com>
wrote:
Hi Gunnar,
Yes, this behaviour is expected since you registered an non-interposed
synchronization. For what purpose are you registering the transaction
synchronization? I would like to be aware of the synchronizations that
we register in WildFly.
The non-interposed sync beforeCompletion callback are invoked first,
then the interposed sync beforeCompletion calls, then the interposed
afterCompletion(int status) calls and finally, the non-interposed
afterCompletion(int status) calls.
The Synchronizations that are registered via the
javax.transaction.TransactionSynchronizationRegistry.registerInterposedSynchronization(Synchronization)
[2] are interposed.
Synchronizations that are registered via the
javax.transaction.Transaction.registerSynchronization(Synchronization)
[3] are non-interposed.
In WildFly, the transaction manager uses the registration order within
the interposed/non-interposed group. Before completion syncs (within
their respective group), are run in registration order. After
completion syncs (within their respective group), are run in reverse
registration order.
I believe that your workaround, mentioned below, of using
JtaPlatform#registerSynchronization() on WildFly, is registering your
synchronization as interposed via the TransactionSynchronizationRegistry
[2]. There might be a way to register a sync callback at the Hibernate
session level (which would also run as interposed sync on WildFly).
Not sure if you saw my email yesterday to Hibernate-dev ml. You should
be aware that the afterCompletion(int status) callback, may be called
from a non-application thread when the WildFly tm reaper handles tx
timeout (this can happen while the application thread is still invoking
calls on the Hibernate session). Because the Hibernate session is not
thread safe, we need to ensure that the Hibernate session
afterCompletion(int status) callback does not mutate the Hibernate
session (e.g. calling session.clear() what status == rolled back).
Scott
[2]
http://docs.oracle.com/javaee/5/api/javax/transaction/TransactionSynchron...
[3]
http://docs.oracle.com/javaee/5/api/javax/transaction/Transaction.html#re...
On 03/10/2015 09:03 AM, Gunnar Morling wrote:
> Hi,
>
> I'm trying to perform a specific action upon transaction rollback.
>
> Assuming this could be done using a custom
> javax.transaction.Synchronization, I tried to register a synchronization as
> follows:
>
> TransactionImplementor transaction = ...; // e.g. a CMTTransaction
> transaction.registerSynchronization( new MySync() );
>
> And indeed beforeCompletion() is invoked as expected. But afterCompletion()
> never is. I debugged this a bit on WildFly and observed the following:
>
> * Hibernate ORM registers RegisteredSynchronization with JTA.
> RegisteredSynchronization manages (indirectly, through
> TransactionCoordinator, SynchronizationRegistry etc.) those
> synchronizations added through o.h.t.Transaction.registerSynchronization()
> * WildFly (specifically, TransactionUtil [1]) registers its own
> SessionSynchronization
> for closing the entity manager/session
>
> Now that second synchronization is called first, closing the session. Upon
> SessionImpl#close(), the SynchronizationRegistry is cleared. Then when
> afterComplection() is called on RegisteredSynchronization afterwards, any
> previously registered delegate synchronizations are gone already and thus
> do not get invoked.
>
> I believe I found a workaround for my case by registering my
> synchronization through JtaPlatform#registerSynchronization() (which
> registers it with the actual JTA transaction).
>
> My questions are:
>
> * Is this behaviour expected?
> * Is the work-around of doing the registration via JtaPlatform viable or
> are there any drawbacks which I'm not aware of?
>
> Thanks,
>
> --Gunnar
>
> [1]
>
https://github.com/wildfly/wildfly/blob/master/jpa/src/main/java/org/jbos...
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/hibernate-dev
>
_______________________________________________
hibernate-dev mailing list
hibernate-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/hibernate-dev