tomee-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Romain Manni-Bucau (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (TOMEE-2043) Thread local transactions are left open across requests
Date Thu, 01 Jun 2017 11:55:04 GMT

    [ https://issues.apache.org/jira/browse/TOMEE-2043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16032855#comment-16032855
] 

Romain Manni-Bucau commented on TOMEE-2043:
-------------------------------------------

if you start the transaction and use propagation then you are the one responsible of finishing
it. So it sounds like tomee impl is good.

> Thread local transactions are left open across requests
> -------------------------------------------------------
>
>                 Key: TOMEE-2043
>                 URL: https://issues.apache.org/jira/browse/TOMEE-2043
>             Project: TomEE
>          Issue Type: Bug
>          Components: TomEE Core Server
>    Affects Versions: 7.0.3
>            Reporter: Svetlin Zarev
>         Attachments: sample.zip
>
>
> @Transactional CDI bean methods annotated with     @Transactional(dontRollbackOn = SomeException.class)
do not commit the transaction at the end of the request/response cycle when the SomeException
exception is thrown. As a result the thread local transaction object is preserved across requests
which makes unrelated requests to fail with "Nested transactions are not supported".
> Sample application that reproduces the issue is attached to the ticket. Just request
the application several times and observe how the output is changing.
> Sample valve that can be used to demonstrate the issue: 
> {code}
> public final class LeakedTransactionDetectionValve extends ValveBase {
>     private static final Logger logger = Logger.getLogger(LeakedTransactionDetectionValve.class.getName());
>     @Override
>     public void invoke(Request request, Response response) throws IOException, ServletException
{
>         boolean hasActiveTransaction = false;
>         try {
>             final Collection<Transaction> transactionsBeforeRequest = getTransactions();
>             for (Transaction transaction : transactionsBeforeRequest) {
>                 if (transaction.getStatus() == Status.STATUS_ACTIVE) {
>                     hasActiveTransaction = true;
>                     break;
>                 }
>             }
>         } catch (Exception ex) {
>             //no-op
>         }
>         getNext().invoke(request, response);
>         if (!hasActiveTransaction) {
>             try {
>                 final Collection<Transaction> transactionsAfterRequest = getTransactions();
>                 for (Transaction transaction : transactionsAfterRequest) {
>                     if (transaction.getStatus() == Status.STATUS_ACTIVE) {
>                         logger.log(Level.SEVERE, "Found active transaction: "
>                                 + request.getRequestURI()
>                                 + "?"
>                                 + request.getQueryString()
>                         );
>                     }
>                 }
>             } catch (Exception ex) {
>                 logger.log(Level.SEVERE, "Failed to determine thread local transaction
status.", ex);
>             }
>         }
>     }
>     Collection<Transaction> getTransactions() throws NoSuchFieldException, IllegalAccessException
{
>         final Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
>         threadLocalsField.setAccessible(true);
>         final Object threadLocals = threadLocalsField.get(Thread.currentThread());
>         final Field tableField = threadLocals.getClass().getDeclaredField("table");
>         tableField.setAccessible(true);
>         final Object table = tableField.get(threadLocals);
>         final Collection<Transaction> transactions = new LinkedList<>();
>         for (int i = 0; i < Array.getLength(table); i++) {
>             final Object entry = Array.get(table, i);
>             if (null != entry) {
>                 final Field valueField = entry.getClass().getDeclaredField("value");
>                 valueField.setAccessible(true);
>                 final Object value = valueField.get(entry);
>                 if (value instanceof Transaction) {
>                     transactions.add((Transaction) value);
>                 }
>             }
>         }
>         return transactions;
>     }
> {code}
> PS: in addition to the issue above, the org.apache.openejb.cdi.transactional.InterceptorBase
must not wrap the exception specified in the "donotRollbackOn" attribute inside TransactionalException



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Mime
View raw message