We store the participants of a transaction in a list. Each Java type representing a participant implements a method called order() which returns an object of type Uid which "effectively" implements the Comparable interface. StartXAResource and EndXAResource return a Uid that is guaranteed to be less than/greater than all other Uid's respectively. I say effectively, since resources that use the last resource commit optimisation are treated slightly differently:
1 Resources that use the last resource commit optimisation will be completed after ones that extend EndXAResource
2 If two participants extend EndXAResource then they will be completed in the same order they were registered with the transaction (and vice versa for ones that implement StartXAResource);
For completeness, I would like to mention that there is an alternate ordering by record type id: each participant has an associated record type (com.arjuna.ats.arjuna.coordinator.RecordType). Records that have lower integer record types are completed first. This ordering is configured in the transaction-jboss-beans.xml file by setting the boolean property AlternativeRecordOrdering on the CoordinatorEnvironment bean.
I do not know why such an alternate ordering is included in the software.
"I do not know why such an alternate ordering is included in the software."
For completeness, records can be processed by Uid as the primary key first and then by type within that, or by type as the primary key and then Uid within that. The ordering by type is the most useful IMO (and the original approach), because it lets you fire off remote invocations first, for instance, before bothering about local invocations. Under the assumption that distributed calls are more likely to fail, you may want to check that they have succeeded before bothering to drive any local participants through 2PC.
I know this is rather an old thread, but I am trying to do pretty much what Kevin is above. Namely, I want to commit my JMS XA resource before my JDBC XA resource in the two-phase commit to avoid the issue described here: http://java.net/jira/browse/JMS_SPEC-28.
It's clear that my JMS XA resource should extend
com.arjuna.ats.jta.resources.StartXAResourcein order to force it to be committed first, but I don't have a clue where to start to make the JMS XAresource extend this interface. I'm using JBoss 4.3.0 EAP CP09 as the application server housing the transaction manager and the messaging server providing JMS (two separate server instances running from the same distribution).
Has anyone successfully managed to use this interface to control the commit order and do you have a list of steps (xml config, classes to extend/register, etc.) that I can follow? Even against JBoss 5 would at least provide some pointers (furthermore, we're planning to upgrade to EAP 5 soon). Any advice would be greatly appreciated.
I could imagine this being a feature that would be well implemented via some configuration in IronJacamar? Perhaps you could raise a question on their forum and point to this thread?
Assuming you're using EAP as JTA, JMS and JCA there is no way to do it without invalidating, or at least stepping outside the scope of, your support agreement. It's not user configurable, it requires non-trivial hacking of the JMS driver code, JCA or both. Try one of the alternatives from http://jbossts.blogspot.com/2011/04/messagingdatabase-race-conditions.html and hassle the Java EE spec folks to get http://java.net/jira/browse/JAVAEE_SPEC-1 done.
Thank you both.
Tom, I'll take a look at Iron Jacamar - it's not something I've looked at before but, even if it doesn't solve my problem, always good to learn new things.
Jonathan, indeed we are using EAP for the lot. Shame. I'll poke the Java EE spec ticket anyway since it's clearly an issue at the spec rather than vendor impl level, so would benefit everyone.
Given our consumer logic on the other side, the best workaround for us is to delay delivery of the message to allow time for the DB commit (see below). Not ideal, since there's no guarantee but since performance is not a biggy for us, we can set the delay to a relatively large time (2000ms) in relation to the average DB commit time (roughly 30 milliseconds).
message.setLongProperty( "JMS_JBOSS_SCHEDULED_DELIVERY", (new Date().getTime() + deliveryDelayMillis));
Hopefully this will catch the majority of cases.
One point I would like to make is that even with a delay (or resource ordering) you wont catch everything:
transaction manager writes its log
databaseXAResource.commit() -> returns XA_RETRY
(in the background we periodically try to comit the database)
Thanks Tom. Very good point - even with the correct resource commit order, this would fail - understood.
In addition to the change we made above (which admittedly is a big old hack), we will be putting a recovery procedure in place to detect failures where the JMS message delivery beats the DB commit for whatever reason. This will be our last resort 'catch all'.