Context
We're upgrading a legacy app from Spring 1.2.8 (yes, for real) to Spring 4.3.6, following best practices and settings things right as we move along. We have everything working up to here except for this bug which required investigation and for which this is the report. Tested on WebSphere 8.5.5 and 9.0. We can't move to Spring 5 yet because of a remaining dependence on Java 7, but I'd be expecting the same behavior from it after looking at the Spring code.
Details
The app is using XML configuration with per-method transaction management declared like so:
<tx:jta-transaction-manager />
[...]
<bean id="SomeApplicationBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
[...]
<property name="transactionAttributes">
<props>
<prop key="getQuestionsList">PROPAGATION_REQUIRED,timeout_60</prop>
Under Spring 4, this results at runtime in WebSphere throwing an exception:
java.lang.IllegalArgumentException: Invalid UOW type: 0
at com.ibm.ws.uow.UOWManagerImpl.setUOWTimeout(UOWManagerImpl.java:706)
at org.springframework.transaction.jta.WebSphereUowTransactionManager.execute(WebSphereUowTransactionManager.java:286)
Explanation
After investigation, it turns out that Spring's JtaTransactionManager tries to use the WebSphere Local Transaction manager (UOW_TYPE_LOCAL_TRANSACTION) whenever possible. However, the WAS Local Transaction manager does not support timeouts.
Excerpt from IBM's javadoc:
Throws: java.lang.IllegalArgumentException - Thrown if the specified type of UOW does not support timeout, e.g. UOW_TYPE_LOCAL_TRANSACTION.
Why it worked before
The Spring 1.2 transaction management was exclusively using the Global Transaction manager, which accepts the declared timeout with no issue.
Workaround
For now, we'll be using our own custom copy of WebSphereUowTransactionManager that'll d avoid using UOW_TYPE_LOCAL_TRANSACTION whenever a timeout is specified for the transaction. Obviously, a baked-in fix would be preferable, I am willing to supply a PR to that effect, although it would be initially against the 4.3 branch.
We'll also be reviewing our declared timeouts for most operations but it is unlikely that we'll get rid of them all.
Comment From: jhoeller
It's not clear to me why UOW_TYPE_LOCAL_TRANSACTION would be used for actual transactions here; we're only really using it to wrap a transaction boundary in PROPAGATION_SUPPORTS scenarios. Is that where you're hitting the timeout problem, or are you running into it for actual PROPAGATION_REQUIRED declarations?
Comment From: jhoeller
Also, I suppose you've been using the plain JtaTransactionManager before, with no need for transaction suspension support on WebSphere? Could you keep using that variant for the time being, ignoring WebSphereUowTransactionManager and its different kind of interaction model completely?
Comment From: fralalonde
The error actually occurs with an operation marked as PROPAGATION_SUPPORTS and not PROPAGATION_REQUIRED as my example implied.
Your observation is very useful as it reduces considerably the number of operations we'd have to review - I only count a handful actual occurences of PROPAGATION_SUPPORTS, some of which already do not specify a timeout.
Comment From: jhoeller
Please note that timeouts are generally only designed for PROPAGATION_REQUIRED and PROPAGATION_REQUIRES_NEW, and not meant to be set for any other propagation level (as documented in TransactionDefinition and the @Transactional annotation). Other transaction manager implementations simply ignore a timeout completely other than for an actual transaction begin.
So the bug in WebSphereUowTransactionManager is that it shouldn't even try to call setUOWTimeout in the UOW_TYPE_LOCAL_TRANSACTION case; it's missing an extra condition on the if statement there. However, the application also shouldn't even declare a timeout on such scopes to begin with since a timeout will never actually be in effect there.
From that perspective, you could simply drop all timeout clauses for PROPAGATION_SUPPORTS definitions in your codebase. Those arguably should never have been there in the first place since they do not have an actual effect with any transaction manager implementation in any version of Spring, as far as I can tell. JtaTransactionManager used to ignore those in Spring 1.2 as well.
Comment From: fralalonde
I vaguely remember using a plain JtaTransactionManager before switching to the standard <tx:jta-transaction-manager />. I was expecting we'd somehow benefit from the WebSphere-specific implementation. Forcing usage of the JtaTransactionManager would be an option, as we actually have little to no WebSphere-specific code of our own (to my knowledge).
Also, I've already raised some doubts within our team as to actual benefits of these timeouts. I've seen the pattern of "leave no property unset / no feature unused" in more than a few places, and I am willing to investigate some these to simplify things.
Also, thank you. Your quick intervention was most unexpected and quite welcome.
Comment From: jhoeller
No problem, good to hear this is helpful. We are going to refine the timeout applicability in WebSphereUowTransactionManager in our upcoming 5.2.7 release and also in our next round of backports. That said, it doesn't look like you'll have to wait for any such patch of ours. Forcing usage of a plain JtaTransactionManager should be a clean way out here, and/or dropping the inapplicable timeout clauses from your PROPAGATION_SUPPORTS definitions (which is generally sensible since those timeouts are otherwise misleading in the code since they'll never have actual effect in a SUPPORTS definition).
Comment From: fralalonde
Yes. I've understood what you meant about timeouts being useless in those cases. Adding the weight of your argument here should help me tip the balance in favor of removing them.
As a general note, upgrading from version to 1 to version 4 was incredibly straightforward - no big surprises. I'm a long time user and Spring still astounds me, both in technology and process. Looking forward to use version 5 and beyond, in both old and new projects.
Comment From: jhoeller
Let's keep this issue open for my planned refinement in WebSphereUowTransactionManager timeout applicability, aligning it with the timeout handling in other transaction manager implementations. A reference back to your original upgrade hurdle here is very useful for that purpose. Thanks for the report, in any case!
Good to hear that the upgrade was so straightforward in general...