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

Work on CAMEL-26327 started by shashank.
----------------------------------------
> camel-core - Routing Slip / Dynamic Router: a redelivered step hangs forever 
> when the route it called used a routing slip or dynamic router itself
> --------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-26327
>                 URL: https://issues.apache.org/jira/browse/CAMEL-26327
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-core
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>
> A routing slip or dynamic router step that is redelivered by the error 
> handler never completes when the route it called ran a routing slip or 
> dynamic router on the same exchange and then failed: the caller waits forever 
> (main 8e0ce2d21371, also 4.22.1 and 4.23.0):
> {code:java}
> errorHandler(defaultErrorHandler().maximumRedeliveries(1).redeliveryDelay(0));
> from("direct:start").routingSlip(constant("direct:sub"));
> from("direct:sub")
>     .doTry()
>         .routingSlip(constant("mock:inner"))
>         .throwException(new IllegalStateException("boom"))
>     .endDoTry()
>     .doFinally()
>     .end();
> template.send("direct:start", e -> e.getMessage().setBody("in"));   // never 
> returns
> {code}
> It needs three things: a routing slip or dynamic router step with redelivery, 
> a called route (direct passes the same exchange) that runs a routing slip or 
> dynamic router, and an exception that leaves that called route. The exception 
> can leave through a {{doTry}} without a matching {{doCatch}}, a route with 
> {{noErrorHandler()}} or a rethrow. A dead letter channel never gets the 
> message, and with {{onException(...).handled(true)}} the result is the same. 
> A {{recipientList}} in the called route, or no redelivery, returns as 
> expected.
> *Cause*
> * {{RoutingSlip.processExchange}} stores the producer of the step in the 
> exchange property {{CamelSlipProducer}} ({{RoutingSlip.java:424}}). The error 
> handler that wraps each step does not call that producer directly: it calls 
> {{RoutingSlipProcessor}}, which reads the producer back from the property on 
> every attempt ({{RoutingSlip.java:582-583}}). {{DynamicRouter}} extends 
> {{RoutingSlip}} and shares this code. (The error handler per step comes from 
> CAMEL-8393; the single error handler around {{RoutingSlipProcessor}} and the 
> property come from CAMEL-12120, which replaced the cache of error handlers 
> that leaked in CAMEL-10048.)
> * When a step completes, its callback removes the property 
> ({{RoutingSlip.java:429}}). A routing slip in the called route runs on the 
> same exchange: it overwrites the outer step's producer and then removes it.
> * The exception then reaches the outer step's error handler, which redelivers 
> ({{RedeliveryErrorHandler.java:1360}}), and {{RoutingSlipProcessor.process}} 
> throws {{NullPointerException: "producer" is null}} 
> ({{RoutingSlip.java:583}}).
> * The redelivery runs as reactive work: {{DefaultReactiveExecutor}} 
> ({{:205-207}}) logs a WARN ending with "This exception is ignored" and the 
> callback is never called. The caller parks in 
> {{DefaultAsyncProcessorAwaitManager.await}} and the exchange stays in flight. 
> CAMEL-26301 is the same lost callback in the tokenizer EIP.
> *Fix* (proposed): {{processExchange}} remembers the producer that was in the 
> property before it sets its own, and the step's callback puts it back (it 
> removes the property only when there was none, so nothing is left on the 
> exchange after the outermost slip, as CAMEL-12120 intended). 
> {{RoutingSlipProcessor}} also fails the exchange with an 
> {{IllegalStateException}} and calls the callback when the property is 
> missing, instead of throwing, so a missing producer cannot turn into a hang 
> again. No other production code sets or reads {{CamelSlipProducer}}.
> Not changed: the nested slip also overwrites the {{CamelSlipEndpoint}} 
> property of the outer slip, so an outer dynamic router that reads it after 
> such a step sees the inner slip's last endpoint. That is not a hang and 
> changing it is visible to routes; it can get its own issue. Also not changed: 
> {{RedeliveryErrorHandler.RedeliveryTask.redeliver()}} calls the output 
> without the try/catch that {{RedeliveryTask.run()}} has for the first 
> attempt, so any asynchronous processor that throws from {{process(exchange, 
> callback)}} on a redelivery hangs the exchange the same way (on the first 
> attempt the exchange fails instead). That is wider than this EIP and can get 
> its own issue.
> *Tests*: {{RoutingSlipNestedSlipRedeliveryTest}} (camel-core, 15 tests, every 
> send bounded with {{assertTimeoutPreemptively}}): routing slip and dynamic 
> router, each calling a route with a routing slip or a dynamic router, with a 
> {{doTry}} at the top of the called route (default error handler) or 
> {{noErrorHandler()}} and a dead letter channel; a handled {{onException}}; an 
> inner step that completes asynchronously; an inner slip step redelivered by 
> the called route's error handler before the outer step is redelivered; the 
> original generated route; the property missing (the new 
> {{IllegalStateException}}); and three controls (a recipient list in the 
> called route, no redelivery, no property left after nested slips). The 12 
> non-control tests time out on main and all pass with the fix. The 
> RoutingSlip, DynamicRouter, redelivery, error handler and dead letter tests 
> of camel-core pass (388 tests).
> *How it was found*: a Rocq specification of Camel's EIPs written from the 
> documentation, compared with real Camel on generated routes. One generated 
> route (a routing slip calling a route with nested {{doTry}}/{{doFinally}} 
> that runs a routing slip, and {{onException}} with redelivery) hung; it was 
> minimised and traced on HotSpot.
> *Affected*: main, 4.23.0 and 4.22.1 reproduced. camel-4.22.x, camel-4.18.x 
> and camel-4.14.x have the same code (set and remove of the property, and the 
> unchecked read in {{RoutingSlipProcessor}}).
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to