[hibernate-dev] JTA synchronizations on WildFly

Gunnar Morling gunnar at hibernate.org
Tue Mar 10 11:44:28 EDT 2015


Hi,

> I believe that your workaround, mentioned below, of using
JtaPlatform#registerSynchronization() on WildFly, is registering your
synchronization as interposed via the TransactionSynchronizationRegistry
[2].

That seems not to be the case. If you check out AbstractJtaPlatform and
TransactionManagerBasedSynchronizationStrategy in ORM,
registerSynchronization() adds the Sync as non-interposed via
TransactionManager.getTransaction().registerSynchronization().

But the ordering is indeed what makes me wonder. As SessionSynchronization
is interposed, the non-interposed beforeCompletion() hooks are run, but the
non-interposed afterCompletion() hooks managed via
RegisteredSynchronization are never run, as the session has been closed and
thus the list of syncs to be invoked through RegisteredSynchronization has
been cleared at this point. At least this behaviour was surprising to me.

My work-around works because my non-interposed sync is added through
JtaPlatform to the actual (Arjuna) Transaction instance directly (rather
than indirectly via RegisteredSynchronization) and thus gets invoked
properly.

2015-03-10 14:39 GMT+01:00 Scott Marlow <smarlow at redhat.com>:

> 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/
> TransactionSynchronizationRegistry.html#registerInterposedSynchronizat
> ion%28javax.transaction.Synchronization%29
>
> [3] http://docs.oracle.com/javaee/5/api/javax/transaction/
> Transaction.html#registerSynchronization%28javax.transaction.
> Synchronization%29
>
>
> 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/jboss/as/jpa/transaction/TransactionUtil.java
>> _______________________________________________
>> hibernate-dev mailing list
>> hibernate-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>>
>>


More information about the hibernate-dev mailing list