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)

Reply via email to