]
Brian Stansberry reassigned WFLY-6885:
--------------------------------------
Assignee: Tom Jenkinson (was: Jason Greene)
Exception swallowed by CmtTxInterceptor if transaction has been
cancelled by reaper
-----------------------------------------------------------------------------------
Key: WFLY-6885
URL:
https://issues.jboss.org/browse/WFLY-6885
Project: WildFly
Issue Type: Bug
Components: EJB, Transactions
Affects Versions: 10.0.0.Final
Reporter: Marcel Kolsteren
Assignee: Tom Jenkinson
Attachments: tx-timeout.zip
The CMTTxInterceptor is responsible for starting a transaction if a public method is
called on a session bean, and for ending it (commit or rollback) after the method has
returned. If a runtime exception occurs during the execution of the public method, WildFly
normally throws an EJBException with the original exception as cause. However, if the
transaction has timed out, it swallows the original exception, and throws a
EJBTransactionRolledBackException without a root cause. That obscures what actually
happened during the execution of the public method.
I attached a zip with an small Arquillian project that shows (1) what happens in case of
an exception in combination with an active transaction (the succeeding test) and (2) what
happens if the exception occurs when the transaction has timed out (the failing test).
I think that the exception swallow is explainable as follows, referring to the
10.0.0.Final version of CMTTxInterceptor, that can be found here
[
https://github.com/wildfly/wildfly/blob/10.0.0.Final/ejb3/src/main/java/o...]
This happens (I verified by stepping through the code with the debugger):
* The catch block of invokeInOurTx is entered.
* The method handleExceptionInOurTx tries to set the "rollback only" status on
the transaction. The result is that the transaction, which has already been rolled back,
stays in the rolled back state. A new EJBException is thrown, wrapping the original
runtime exception.
* The finally block of invokeInOurTx is entered.
* The endTransaction method sees that the transaction is in the rolled back state, and
concludes that the "reaper canceled (rolled back) tx case" is applicable. It
throws a new exception (which replaces the EJBException that just has been thrown), but
that new exception doesn't have a cause.
The desired behavior would be that the interceptor only wraps the original exception in
an EJBException in this case. I think that the invokeInOurTx method should only call the
endTransaction method, if the transaction is not in the rolled back state.