users@jpa-spec.java.net

[jpa-spec users] [jsr338-experts] Re: Fwd: Re: Follow up discussion about transaction time out, background transaction roll back and ordering issue with detaching entities from persistence context...

From: Scott Marlow <smarlow_at_redhat.com>
Date: Thu, 25 Sep 2014 11:33:24 -0400

On 09/08/2014 10:57 AM, Scott Marlow wrote:
> On 09/07/2014 09:43 PM, Scott Marlow wrote:
>> Please read response from Evan Ireland below.
>>
>> -------- Original Message --------
>> Subject: [jsr338-experts] Re: Follow up discussion about transaction
>> time out, background transaction roll back and ordering issue with
>> detaching entities from persistence context...
>> Date: Sun, 7 Sep 2014 20:43:37 +0000
>> From: Ireland, Evan <evan.ireland_at_sap.com>
>> Reply-To: jsr338-experts_at_jpa-spec.java.net
>> To: jsr338-experts_at_jpa-spec.java.net <jsr338-experts_at_jpa-spec.java.net>
>>
>> Scott,
>>
>> Perhaps an approach that could be taken is for the transaction (which is
>> to be "rolled back" by a background thread, not the "owning" thread) to
>> be marked with status STATUS_MARKED_ROLLBACK or STATUS_ROLLING_BACK
>> (from the JTA status point of view), whereas the actual backend
>> transaction (at least in the case of STATUS_ROLLING_BACK) could be
>> already rolled back.
>
> I'm not following how the (background thread) transaction manager would
> know to mark the transaction as STATUS_ROLLING_BACK (implies that
> something knows to later mark the transaction as STATUS_ROLLEDBACK). I'm
> also not sure of when the transaction is rolled back and
> Synchronization.afterCompletion(int) called for this idea.
>
> For the suggestion of STATUS_MARKED_ROLLBACK, I think that could help in
> certain cases but not all (e.g. having the transaction rolled back
> immediately to break deadlocks).
>
>>
>> By playing with status codes and having a sort of limbo state, perhaps
>> we can avoid contract violation.
>
> I'm not sure that changing the transaction status to any of the current
> status codes available helps. In theory, the application (owning)
> thread may check the transaction status and see STATUS_ACTIVE
> (application still could add another entity to persistence context).
> Also, the persistence providers really do not have control over the
> determination of what the transaction status code is set to.
>
> As mentioned below, one side effect of rolling the transaction back in a
> background thread (which involves running the interposed/non-interposed
> Synchronization.afterCompletion calls), is that an entity class could be
> added after the persistence context detaches other entities from the
> persistence context.
>
> Before we get far into possible solutions, do we agree that this is a
> situation that should be prevented? I think it should be prevented but
> I really would like to hear what others think and why we should guard
> against this potential issue.

If others are interested in addressing this issue in JPA 2.2/EE 8, would
be great to hear from you, as I think the cost to solve this is not small.

One possible improvement, might be adding a way to know if a transaction
timed out. TransactionSynchronizationRegistry.wasTimedOut() could
return true if the active thread was timed out. With this knowledge, we
at least know that we are in this situation but what should we then do?
  Some ideas:

1). If TransactionSynchronizationRegistry.wasTimedOut() returns true in
Synchronization.afterCompletion(int), mark the persistence context as
doomed, so that no further invocations can occur until the application
thread clears the doomed state.

2). If TransactionSynchronizationRegistry.wasTimedOut() returns true in
Synchronization.afterCompletion(int), mark the persistence context as in
need of being cleared. This is really the same thing as the doomed
state but might sound better.

I'm not sure that the method name
TransactionSynchronizationRegistry.wasTimedOut(), is the best that we
can suggest. What we need is a way to know if the transaction manager
is cancelling the transaction in the background.

One distinction, is in the distributed (with propagated JTA transaction)
case, if a remote JVM rolls back the transaction, when the remote JVM
calls the other JVM to roll back the transaction,
TransactionSynchronizationRegistry.wasTimedOut() should return false
(since the rollback was requested by the application or container, not
the transaction manager).

>
> For me, I would like to improve the robustness of EE application servers
> environments to avoid invalid application state when JTA transactions
> time out (for both BMT + CMT applications). I'm mentioning CMT even
> though I couldn't actually reproduce a problem with my CMT test case).

Correction, my test case reproduces the issue with a UserTransaction,
Servlet + JPA. I didn't reproduce the issue with EJB3 yet (CMT or BMT)
but am still concerned that the ordering issue could cause invalid state
to appear in an EJB.

The only reason that I have heard so far, that CMT/BMT wouldn't see
invalid state, is that the EJB container is likely to notice that the
JTA transaction is no longer active, before the application thread can
mutate the bean state via an entity manager invocation (concern would be
if an entity is added to the persistence context after managed entities
are detached from persistence context in the background thread).

>
>>
>> -----Original Message-----
>> From: Scott Marlow [mailto:smarlow_at_redhat.com]
>> Sent: Saturday, 6 September 2014 3:48 a.m.
>> To: jsr338-experts_at_jpa-spec.java.net
>> Subject: [jsr338-experts] Follow up discussion about transaction time
>> out, background transaction roll back and ordering issue with detaching
>> entities from persistence context...
>>
>> Hi,
>>
>> I created a few test cases that try to simulate what could happen, when
>> JTA transaction time-out leads to a background thread rolling the
>> transaction back. I was able to recreate the situation, where the
>> application thread is able to (I believe) violate "7.9.2 Provider
>> Responsibilities" for when background thread rolls back by simulating an
>> edge case where the application thread adds an entity after the
>> roll-back occurs.
>>
>> Here is my example servlet service method that starts a user
>> transaction, times out and simulates how application thread could add
>> entities after roll back (based on [1]):
>>
>> @Resource
>> private UserTransaction userTransaction;
>>
>> @PersistenceUnit
>> private EntityManagerFactory entityManagerFactory;
>>
>> doGet(...) {
>> userTransaction.setTransactionTimeout(5); // 5 second timeout
>> userTransaction.begin();
>> EntityManager entityManager =
>> entityManagerFactory.createEntityManager();
>> entityManager.joinTransaction(); // already joined but...
>>
>> boolean notRolledBackException = false;
>> while (!notRolledBackException) {
>> Thread.sleep(10 * 1000);
>> int transactionStatus = userTransaction.getStatus();
>> if ( transactionStatus == Status.STATUS_ROLLEDBACK) {
>> // simulate race condition by adding entity after rollback
>> Employee emp = new Employee();
>> emp.setId(id);
>> emp.setAddress(address);
>> emp.setName(name);
>> entityManager.persist(emp);
>> }
>> // application has invalid state as the persistence context
>> // has an Employee entity that was not detached.
>> }
>>
>> The above illustrates my concern of a deeper issue that we should
>> address in EE 8. I don't think we have control of when the entities are
>> cleared from the persistence context after a background thread rolls the
>> transaction back, as the application/background threads are not
>> controlled by any ordering requirements. In other words, I think that
>> the background thread may clear the persistence context of entities
>> before the application thread is about to add another entity to the
>> persistence context.
>>
>> From a standards point of view, I also found that there is no way to
>> know whether the thread that is rolling back the transaction, is a
>> communications thread (on behalf of remote JVM participating in same TX)
>> or a local "timer" thread. Or if the thread rolling back the
>> transaction is the application thread. I have some ideas of how this
>> could be addressed but would like to first confirm with others on this
>> list that we should address this situation for JPA.next/EE 8.
>>
>> I also tried to recreate the above situation with stateful session beans
>> + a CMT but was unable to due to various transaction status checks
>> already in our EJB container. In theory, we might also see see the same
>> problem with EJB CMT but I was unable to recreate it.
>>
>> Thanks,
>> Scott
>>
>> [1]
>> https://github.com/scottmarlow/wildfly/tree/transactiontimeout_clientut_noejb
>>
>>
>> creates a UT from a servlet with a 5 second TX time out and the
>> application thread adds entities to the persistence context after the
>> transaction has been rolled back.
>>
>>
>