Hi John and Paul,
Sorry for the delay in response.
Regards,
Paul
On Nov 28, 2012, at 4:15 AM, Paul Robinson wrote:
> Jonathan,
>
> On 27 Nov 2012, at 17:14, Jonathan Halliday <jonathan.halliday_at_redhat.com> wrote:
>
>>
>>
>> 1) I'm undecided if I love or hate that 'active' finally has an explicit definition in terms of its Status set. I know I loathe that the set of States that define it includes UNKNOWN though.
>>
>> As for the rest, I love it because it removes ambiguity, but I hate it because the existing spec does not so define 'active' or 'inactive' in relation to transaction contexts and the expected behaviour of existing methods in the API.
>>
>> The existing spec leaves scope for differing interpretation, from 'an active transaction is one with Status.STATUS_ACTIVE only' through 'an active transaction is one that has not yet terminated, i.e. also includes Status.STATUS_MARKED_ROLLBACK and possibly other non-terminal states.
>>
>> Considered in isolation, the strict definition of 'active' in relation to transaction scope is a Good Thing. My concern is that when read as part of the overall spec, it may be interpreted as being intended to apply the same definition to 'active' in terms of transaction context also, i.e. be thought to retroactively define how the term should be interpreted elsewhere in the spec.
>>
>> I'd be strongly inclined to remove this possible implication by retrofitting the spec preamble with a brief comment on the intended definition of the terms 'active' and 'inactive' in relation to transaction contexts (i.e. use other than in relation to the new transaction scopes). If that definition should be strict or loose is outside the scope of this discussion. Perhaps it should just make clear that it's not intended that the terms as defined in relation to transaction scope should also apply to its use in relation to transaction context/lifecycle.
>>
Indeed I had thought of all of these exact points as well and I think the qualification/bounding of what active means in this TransactionScoped context is the cleanest, safest and least intrusive way to make this distinction. "It is not intended that the terms "active" and as defined in relation to TransactionScope should also apply to its use in relation to transaction context, lifecycle, etc. mentioned elsewhere in this specification". I guess another option would be to just use another term altogether such as "live" but I think this clarifying sentence works.
>
>>
>> 2) There is a known issue with the behaviour of containers and applications as regards the asynchronous processing of transaction termination. Essentially a Thread's tx Status or context can change without warning, if another Thread acts concurrently on that context. This occurs primarily if a tx timeout is processed in the background, although as app concurrency increases I suspect we'll see it happen more due to the actions of concurrent application Threads also. It causes problems with e.g. a JDBC Connection handle that previously was under transaction control suddenly reverting to local-tx auto-commit mode. Fixing this is itself a matter for spec revision, but let's limit the discussion to transaction scopes for now.
>>
>> By the same reasoning, the tx scope a Thread is running in may change other than through that Thread's actions. At minimum the user should be made aware of this problem so that they can make some effort to code defensively. At best it should be ensured that harmful side effects are not permitted. The JDBC Connection handle thing for example would be fine if the Connection handle was closed or otherwise invalidated instead of reverting to auto-commit, since the app would then detect the tx status change indirectly via an attempted action on the Connection throwing an exception. It may be that a 'null scope' or some similar pseudo environment exists for use where the tx scope is undefined.
>>
>> Passing a managed handle/reference of any sort obtained in one tx scope across a tx scope boundary to another tx scope (even unwittingly on the same Thread, such as in the async Status change case) should make clear the expected semantics of that handle in its new environment, or you'll wind up having the same problem with scopes that currently exists with contexts.
>>
>> The javadoc mention of 'associated where first used' and 'across suspend/resume' could be extended to treat tx context change as equivalent to a suspend/resume even where such methods are not explicitly called, which may be what's intended?
>
> I wondered about this problem too and asked Pete Muir about it. It seems like we should be ok as Weld and other CDI implementations use a proxy for the injected bean. Providing all calls to the bean go through the proxy, the right bean instance should be selected, no matter what changes another thread has made to the transaction state.
>
> But IMO, the other problem that you suggest does hold. Developers will need to code defensively as two calls in succession to the same injected bean may not result in calls on the same bean instance. For example:
>
> @TransactionScoped SomeBean myBean;
> ...
> myBean.set(2);
> //Another thread changes the status of the transaction
> myBean.get(); //Would fail if no transaction active, or return some other value if another transaction active.
This, if I understand you correctly, is the expected behavior re "The contextual references used across different JTA transactions are distinct."
>
>>
>>
>> 3) Is it felt necessary to address the behaviour of scopes in distributed (i.e. multi-JVM) transactions? This is not the case for TSR get/put behaviour for example, with most implementations opting to consider the TSR storage to be node local, hence not allowing a put in one container to be visible to a get in anther container, even if the logical transaction context is equivalent. I think it's reasonable for scopes to behave likewise, but do we want to enforce that they should (or should not)?
>
> I agree that it's reasonable for scopes to be node-local. However, I seem to remember that CDI scopes, and the associated bean instances, can span multiple JVMs. I'm struggling to find a reference to this so I may have misunderstood.
Good point. I'm waiting to hear back from CDI folks as to whether we inherit this behavior from CDI or need to call it out explicitly in JTA. Have you found anything by chance?
>
>>
>> Speaking of TSR, it seems the tx-context-local Map underpinning the TSR.get/put methods may be a likely candidate for use in implementation of scopes, forming a handy place to cache resolved references or such. Is it necessary/desirable to tweak the TSR definition to ensure this implementation route is possible? I guess that loops back to the earlier discussion on 'active' in relation to tx contexts rather than tx scopes - it would be necessary to ensure consistency between the behaviour of TSR.get/put and the definition used by scopes.
Indeed we are using TSR for our implementation. Is there anything specific that you think/say would be necessary beyond what exists in order to ensure this is possible/consistent?
>>
>>
>> Jonathan.
>>
>> On 11/27/2012 03:48 PM, Paul Parkinson wrote:
>>> Hi,
>>>
>>> Below is a rough first run of JTA 1.2 section
>>> 3.8 TransactionScoped Annotation, http://java.net/jira/browse/JTA_SPEC-7 .
>>>
>>> These two issues remain open:
>>>
>>> 1. Do we want to keep the scope open until after
>>> Synchronization.afterCompletion completes? There is no transaction
>>> available in afterCompletion, but developers may need to do tidy-up on
>>> the TransactionScoped beans that will no longer be available. If users
>>> include a @PreDestroy method to do cleanup after the transaction has
>>> completed the spec needs to be clear that the transaction has completed
>>> when the @PreDestroy method is called.
>>>
>>> 2. Is the transaction scope itself volatile and not recoverable? It
>>> would seem so. Do we make the chosen behaviour explicit in the spec?
>>>
>>> Thank you for any feedback on these open issues as well as any feedback
>>> on the spec draft in general (eg suggestions as far as the example
>>> presented) as we need to close this down in the next couple weeks.
>>>
>>> Thanks,
>>> Paul
>>>
>>>
>>>
>>>
>>> 3.8 TransactionScoped Annotation
>>>
>>> The javax.transaction.TransactionScoped annotation provides the ability
>>> to specify a standard scope to define beans whose lifecycle are scoped
>>> to the currently active JTA transaction.
>>> The transaction scope is active when the return from a call
>>> to UserTransaction.getStatus or TransactionManager.getStatus is one of
>>> the following states:
>>> Status.STATUS_ACTIVE
>>> Status.STATUS_MARKED_ROLLBACK
>>> Status.STATUS_PREPARED
>>> Status.STATUS_UNKNOWN
>>> Status.STATUS_PREPARING
>>> Status.STATUS_COMMITTING
>>> Status.STATUS_ROLLING_BACK
>>>
It is not intended that the term "active" as defined here in relation to TransactionScope should also apply to its use in relation to transaction context, lifecycle, etc. mentioned elsewhere in this specification.
>>> The transaction context is destroyed after
>>> any Synchronization.beforeCompletion methods are called
>>> and afterCompletion calls have been made on enlisted resources.
>>> Synchronization.afterCompletion calls may occur before the transaction
>>> context is destroyed, however, there is no guarantee.
>>>
>>> A javax.enterprise.context.ContextNotActiveException will be thrown if
>>> an object with this annotation is used when the transaction context is
>>> not active. The object with this annotation is associated with the JTA
>>> transaction where it is first used and this association is retained
>>> through any transaction suspend or resume calls as well as any
>>> beforeCompletion Synchronization calls until the transaction is
>>> completed. The way in which the JTA transaction is begun and completed
>>> (eg BMT, CMT, etc.) is of no consequence. The contextual references used
>>> across different JTA transactions are distinct. The following example
>>> test cases illustrate the expected behavior:
>>>
>>> TransactionScoped annotated CDI managed bean:
>>>
>>>
>>> @TransactionScoped
>>>
>>> public class TestCDITransactionScopeBean {
>>>
>>> public void test() { //...
>>>
>>> }
>>>
>>> }
>>>
>>>
>>>
>>> Test Class:
>>>
>>>
>>> UserTransaction userTransaction;
>>>
>>> TransactionManager transactionManager;
>>>
>>> @Inject
>>>
>>> TestCIDTransactionScopeBean TestCIDTransactionScopeBean;
>>>
>>>
>>> public void testTxAssociationChange() throws Exception {
>>>
>>> userTransaction.begin(); //tx1 begun
>>>
>>> testTxAssociationChangeBean.test();
>>> //testTxAssociationChangeBean instance has tx1 association
>>>
>>> Transaction transaction = transactionManager.suspend(); //tx1
>>> suspended
>>>
>>> //assert testTxAssociationChangeBean still associated with tx1
>>> and that no transaction scope is active.
>>>
>>> userTransaction.begin(); //tx2 begun
>>>
>>> testTxAssociationChangeBean.test(); //assert new
>>> testTxAssociationChangeBean instance has tx2 association
>>>
>>> userTransaction.commit(); //tx2 committed, assert no
>>> transaction scope is active
>>>
>>> transactionManager.resume(tx); //tx1 resumed
>>>
>>> testTxAssociationChangeBean.test();
>>>
>>> //assert testTxAssociationChangeBean is original tx1 instance
>>> and not still referencing committed/tx2 tx
>>>
>>> userTransaction.commit(); //tx1 commit, assert no transaction
>>> scope is active
>>>
>>> try {
>>>
>>> testTxAssociationChangeBean.test(); fail(“should have thrown
>>> ContextNotActiveException”);
>>>
>>> } catch (ContextNotActiveException ContextNotActiveException) {
>>>
>>> // do nothing intentionally
>>>
>>> }
>>>
>>> }
>>>
>>>
>>>
>>> “Java Transaction API Reference” on page 30 has a full description of
>>> this annotation
>>>
>>> [...]
>>>
>>>
>>> /**
>>> * Annotation used to indicate a bean is to be scoped to the currently
>>> active
>>> * JTA transaction.
>>> *
>>> * The transaction scope is active when the return from a call to
>>> * <code>UserTransaction.getStatus</code> or
>>> * <code>TransactionManager.getStatus</code>
>>> * is one of the following states:
>>> * <li>Status.STATUS_ACTIVE</li>
>>> * <li>Status.STATUS_MARKED_ROLLBACK</li>
>>> * <li>Status.STATUS_PREPARED</li>
>>> * <li>Status.STATUS_UNKNOWN</li>
>>> * <li>Status.STATUS_PREPARING</li>
>>> * <li>Status.STATUS_COMMITTING</li>
>>> * <li>Status.STATUS_ROLLING_BACK</li>
>>> *
>>> * The transaction context is destroyed after any
>>> * <code>Synchronization.beforeCompletion</code> methods are called and
>>> * afterCompletion calls have been made on enlisted resources.
>>> * <code>Synchronization.afterCompletion</code> calls may occur before
>>> * the transaction context is destroyed, however, there is no guarantee.
>>> *
>>> * A <code>javax.enterprise.context.ContextNotActiveException</code>
>>> * will be thrown if an object with this annotation is used when the
>>> * transaction context is not active.
>>> * The object with this annotation is associated with the JTA
>>> transaction where
>>> * it is first used and this association is retained through any
>>> transaction
>>> * suspend or resume calls as well as any beforeCompletion Synchronization
>>> * calls until the transaction is completed.
>>> * The way in which the JTA transaction is begun and completed
>>> * (eg BMT, CMT, etc.) is of no consequence.
>>> * The contextual references used across different JTA transactions are
>>> * distinct.
>>> *
>>> * @since JTA1.2
>>> */
>>> @Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
>>> @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
>>> @NormalScope(passivating=true)
>>> public @interface TransactionScoped {
>>> }
>>
>> --
>> Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham (USA), Mark Hegarty (Ireland), Matt Parson
>> (USA), Charlie Peters (USA)
>
> --
> Paul Robinson
> Web Service Transactions Lead
> paul.robinson_at_redhat.com
>
> JBoss, a Division of Red Hat
> Registered in England and Wales under Company Registration No. 03798903
> Directors: Michael Cunningham (USA), Brendan Lane (Ireland), Matt Parson
> (USA), Charlie Peters (USA)
>