Claus Ibsen created CAMEL-24980:
-----------------------------------

             Summary: camel-core - RedeliveryErrorHandler: remove dead 
SimpleTask code and share failure handling between the tasks
                 Key: CAMEL-24980
                 URL: https://issues.apache.org/jira/browse/CAMEL-24980
             Project: Camel
          Issue Type: Improvement
          Components: camel-core
            Reporter: Claus Ibsen


RedeliveryErrorHandler (core/camel-core-processor, ~2050 lines) is hard to 
maintain. Most of the class is two inner task classes, SimpleTask and 
RedeliveryTask, that each carry their own copy of the failure handling logic, 
and the copies have started to drift apart. This ticket is about cleaning that 
up without changing behaviour.

h3. Findings

*Dead code in SimpleTask*
The CAMEL-22907 fix added about 300 lines to SimpleTask.handlePreviousFailure 
and its helpers: exception policy lookup, deliverToFailureProcessor, 
shouldHandle / shouldContinue, the 4-arg prepareExchangeAfterFailure and 
prepareExchangeForContinue. None of it can run. SimpleTask is only chosen when 
there are no exception policies and no dead letter channel (see doStart), so 
the policy lookup always returns null and the target processor is always null. 
With the old 4-line body put back, all 12 *BridgeErrorHandler* tests still 
pass, including the two added by CAMEL-22907.

*Duplicated logic that has drifted*
- handleException: SimpleTask checks for a null exception, RedeliveryTask does 
not.
- FAILURE_ROUTE_ID is set three different ways: getRoute().getRouteId(), 
getAtRouteId() and ExchangeHelper.captureFailureOrigin().
- The two prepareExchangeForContinue methods behave differently. One removes 
EXCEPTION_CAUGHT and sets EXCEPTION_HANDLED, the other keeps EXCEPTION_CAUGHT.
- In each task, deliverToFailureProcessor has a "with failure processor" branch 
and a "without" branch that both set the failure endpoint and route id, run 
onPrepare and build the log message. That is four near-identical blocks in 
total.

*Logging*
- logFailedDelivery takes five positional booleans (shouldRedeliver, 
newException, handled, continued, isDeadLetterChannel). isDeadLetterChannel is 
never used, and isLogRetryAttempted is checked twice.

*Ordering and task release*
- In deliverToFailureProcessor the finally block schedules the callback before 
it logs and releases the task. DefaultReactiveExecutor runs the task 
immediately when no worker is active on that thread, so when an async failure 
processor finishes on another thread, the exchange can carry on routing before 
the "Failed delivery" log reads it. Not reproduced yet.
- When run() catches an unexpected exception, or runSynchronousRedelivery is 
interrupted, the callback is fired but taskFactory.release is never called.
- RedeliveryTask.reset() does not clear failureProcessor, so a reused pooled 
task can send a later exchange to an earlier exchange's onException route. This 
only affects the pooled exchange factory, which is planned for deprecation. It 
is a one-line fix to fold into this cleanup.

h3. Proposed work (one PR per step)

# Delete the dead SimpleTask code by going back to the pre-CAMEL-22907 body. 
Keep the CAMEL-22907 tests as guards.
# Replace the five booleans with a failed-delivery logger driven by an enum 
(retry, exhausted, handled, continued, new exception).
# Move the shared failure preparation into one helper (failure endpoint, route 
id, onPrepare, original message/body, handled/continued preparation) that both 
tasks use. Collapse the two branches of deliverToFailureProcessor into one path.
# Log and release the task before the callback is scheduled, and release the 
task on the error paths.
# Optional: turn the decision part of RedeliveryTask.doRun into a small pure 
method that can be unit-tested on its own.

h3. Constraints
- This is on every exchange's hot path. Keep hot methods small so the JIT can 
inline them (as the earlier "refactor large methods to help inlining" commit 
did), and do not add allocations.
- Within Camel, the only subclasses outside the package are 
TransactionErrorHandler (camel-spring) and JtaTransactionErrorHandler. They 
only call super.process, so the inner tasks can become private. 
RedeliveryErrorHandler itself is public API, so keep its protected methods for 
third-party subclasses.
- No behaviour change is intended. The existing error handler tests in 
camel-core are the safety net.

_Claude Code on behalf of Claus Ibsen_




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to