You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Nick Houghton (JIRA)" <ji...@apache.org> on 2017/02/28 02:32:45 UTC

[jira] [Created] (CAMEL-10902) TransactionErrorHandler treats all exceptions as a rollback (different to Spring)

Nick Houghton created CAMEL-10902:
-------------------------------------

             Summary: TransactionErrorHandler treats all exceptions as a rollback (different to Spring)
                 Key: CAMEL-10902
                 URL: https://issues.apache.org/jira/browse/CAMEL-10902
             Project: Camel
          Issue Type: Bug
          Components: camel-spring
    Affects Versions: 2.18.2
            Reporter: Nick Houghton
            Priority: Minor


It appears while debugging a JDBC transaction commit issue that the behaviour of TransactionErrorHandler is different to the expected behaviour of the underlying Spring TransactionTemplate classes. I'm not sure this is by design or not?

The standard @Transactional annotation people are used to will only rollback a transaction when a RuntimeException is caught, in all other cases it will commit, this appears to be different to camels abstraction which will rollback if there is any exchange.getException() || exchange.isRollback() set. Should this be more consistent with the underlying Spring impl and be an instanceof RuntimeException instead?

Currently:

{code}
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // wrapper exception to throw if the exchange failed
                // IMPORTANT: Must be a runtime exception to let Spring regard it as to do "rollback"
                RuntimeException rce;

                // and now let process the exchange by the error handler
                processByErrorHandler(exchange);

                // after handling and still an exception or marked as rollback only then rollback
                if (exchange.getException() != null || exchange.isRollbackOnly()) {

                    // wrap exception in transacted exception
                    if (exchange.getException() != null) {
                        rce = ObjectHelper.wrapRuntimeCamelException(exchange.getException());
                    } else {
                        // create dummy exception to force spring transaction manager to rollback
                        rce = new TransactionRollbackException();
                    }

                    if (!status.isRollbackOnly()) {
                        status.setRollbackOnly();
                    }

                    // throw runtime exception to force rollback (which works best to rollback with Spring transaction manager)
                    if (log.isTraceEnabled()) {
                        log.trace("Throwing runtime exception to force transaction to rollback on {}", transactionTemplate.getName());
                    }
                    throw rce;
                }
            }
        });
{code}

Could be:
{code}
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // wrapper exception to throw if the exchange failed
                // IMPORTANT: Must be a runtime exception to let Spring regard it as to do "rollback"
                RuntimeException rce;

                // and now let process the exchange by the error handler
                processByErrorHandler(exchange);

                // after handling and still an exception or marked as rollback only then rollback
                if (exchange.getException() instanceof RuntimeException || exchange.isRollbackOnly()) {

                    // wrap exception in transacted exception
                    if (exchange.getException() != null) {
                        rce = ObjectHelper.wrapRuntimeCamelException(exchange.getException());
                    } else {
                        // create dummy exception to force spring transaction manager to rollback
                        rce = new TransactionRollbackException();
                    }

                    if (!status.isRollbackOnly()) {
                        status.setRollbackOnly();
                    }

                    // throw runtime exception to force rollback (which works best to rollback with Spring transaction manager)
                    if (log.isTraceEnabled()) {
                        log.trace("Throwing runtime exception to force transaction to rollback on {}", transactionTemplate.getName());
                    }
                    throw rce;
                }
            }
        });
{code}

This enable my desired behaviour where a subroute can throw an exception to present an error to the user, but still have work committed if desired.

At the moment it seems like the only option for not rolling back a transaction is to process the exception in the subroute itself, which is not what I want to do rather than letting it bubble up to the calling route.

If not the given change, would it be possible to allow what drives a rollback to be configurable? much like Spring 'rollbackFor' parameter.



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