[ 
https://issues.apache.org/jira/browse/CAMEL-26328?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Work on CAMEL-26328 started by shashank.
----------------------------------------
> camel-core - Failover load balancer: fails over on an exception that is only 
> suppressed (such as one thrown in a doFinally) and drops the exception that 
> failed the attempt
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-26328
>                 URL: https://issues.apache.org/jira/browse/CAMEL-26328
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-core
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Minor
>
> The failover load balancer with a list of exceptions fails over when the 
> exception that failed the attempt is not in the list but one of its 
> *suppressed* exceptions is. Since CAMEL-25114 (4.23.0) an exception thrown in 
> a {{doFinally}} block is added as a suppressed exception to the pending 
> exception of the {{doTry}} block, so a cleanup step that throws one of the 
> listed types now makes the load balancer fail over. When the next processor 
> succeeds, the exception that failed the attempt is lost and the route goes on 
> (main ffab48ea514b):
> {code:java}
> from("direct:start")
>     .loadBalance().failover(IllegalArgumentException.class)
>         .to("direct:attempt")
>         .to("mock:second")
>     .end()
>     .to("mock:after");
> from("direct:attempt")
>     .doTry()
>         .throwException(new IOException("original"))
>     .doFinally()
>         .throwException(new IllegalArgumentException("cleanup"))
>     .end();
> main / 4.23.0: exception=null, mock:second=1, mock:after=1   (failed over on 
> the doFinally exception, IOException lost)
> 4.22.1:        exception=IOException("original"), no failover
> {code}
> The same happens when the {{doFinally}} calls a route that throws. 
> {{onException(IllegalArgumentException.class)}} and 
> {{doCatch(IllegalArgumentException.class)}} do not match this IOException: 
> they look at the exception and its causes only (doTry-eip.adoc, "How doCatch 
> matches an exception"; {{DefaultExceptionPolicyStrategy}} and 
> {{CatchProcessor}} walk {{ObjectHelper.createExceptionIterable}}). The 
> failover page says the load balancer "can be configured to only apply for a 
> specific set of exceptions", and does not mention suppressed exceptions.
> *Cause*: {{FailOverLoadBalancer.shouldFailOver}} checks each listed type with 
> {{exchange.getException(type)}}. That goes to 
> {{ObjectHelper.getException(Class, Throwable)}}, which looks at the 
> suppressed exceptions first, then at the cause chain. That lookup was added 
> for CAMEL-6406 (2.16.0) as a general API change, not for failover. Before 
> CAMEL-25114 the suppressed exceptions that camel-core added on the routing 
> path were mostly the other way round: when an {{onException}} block fails 
> while it handles an exception, {{FatalFallbackErrorHandler}} adds the 
> original exception as a suppressed exception to the new one (also on 
> camel-4.22.x), so there the suppressed exception is the one the attempt first 
> failed with. A failing {{onCompletion}} in {{modeBeforeConsumer}} also adds 
> its exception as suppressed (camel-4.22.x too). The CAMEL-25114 PR did not 
> look at the load balancer.
> *Fix* (proposed): {{shouldFailOver}} matches the listed types against the 
> exception and its causes only, with {{ObjectHelper.createExceptionIterable}}, 
> as {{onException}} and {{doCatch}} do. A paragraph on the failover EIP page 
> (and its catalog copy), and a 4.24 upgrade guide entry, because a listed 
> exception that is only suppressed no longer causes failover in these cases 
> either: an {{onException}} block that fails while it handles a listed 
> exception (the exchange fails with the new exception), a {{doCatch}} whose 
> {{onWhen}} throws (since CAMEL-25114 the exchange fails with the predicate's 
> exception, the original one suppressed), and a processor or component that 
> adds one itself. A route that relied on it adds the type of the exception the 
> attempt fails with to the list. Not changed: 
> {{ThrottlingExceptionRoutePolicy}} checks its {{throttledExceptions}} with 
> the same {{exchange.getException(type)}} loop (a follow-up).
> *Tests*: {{FailOverLoadBalanceSuppressedExceptionTest}} (camel-core, 11 
> tests). A doFinally that throws a listed exception, a doFinally that calls a 
> route that throws one, the same with inheritErrorHandler, round robin and 
> maximumFailoverAttempts, a processor that adds one as suppressed, an 
> onException block that fails while handling a listed exception, and a doCatch 
> whose onWhen throws: no failover, and the exchange fails with the exception 
> of the attempt with the listed one as its suppressed exception. These 6 fail 
> on main and pass with the fix. Controls that pass on both: a listed exception 
> as the cause of an unlisted one fails over, a listed exception thrown 
> directly fails over, a listed exception from doTry with an unlisted one from 
> doFinally fails over, an unlisted exception does not, and {{onException}} 
> does not match the suppressed exception. The load balancer, failover and 
> doTry/doCatch/doFinally tests of camel-core pass (196 tests).
> *How it was found*: a Rocq specification of Camel's EIPs written from the 
> documentation, compared with real Camel on generated routes (a failover 
> monitoring IllegalArgumentException whose attempt's doFinally called a route 
> that threw one), then reproduced on HotSpot against 4.22.1 and main.
> *Affected*: the doFinally case: 4.23.0 and main (camel-4.22.x does not add 
> the doFinally exception as suppressed; 4.22.1 checked). A processor or 
> component that adds a suppressed exception itself: every version since 
> 2.16.0. A failing {{onCompletion}} in {{modeBeforeConsumer}}: 4.0.0 and later 
> (checked on the 4.0.0 tag).
> _Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to