allthingssecurity opened a new pull request, #29295: URL: https://github.com/apache/camel/pull/29295
# Description [CAMEL-26601](https://issues.apache.org/jira/browse/CAMEL-26601) Follow-up of CAMEL-26464 (#29127): the one case it does not cover, a recipient of a recipient list inside a `doTry`. In a `doTry`, `MulticastProcessor.wrapInErrorHandler` does not put an error handler around a recipient; the recipient only gets the unit of work processor (a `CamelInternalProcessor`). For a multicast that output is a channel, which catches a throw since CAMEL-26464. For a recipient list it is the producer of the recipient endpoint. When that producer throws from `process(exchange, callback)` instead of setting the exception on the exchange, the exception reaches the sub task, the reactive executor logs and drops it, and the recipient list never completes. The `doCatch` never runs, and the caller waits for good. This holds with the default options and with `synchronous`, `parallelProcessing`, `stopOnException` and `shareUnitOfWork`. With a `timeout`, the recipient list returns after the timeout without the failure, so the `doCatch` does not run there either. Camel's own seda producer does this: with a bounded queue that is full, and neither `blockWhenFull` nor `discardWhenFull` set (the default), it throws `IllegalStateException: Queue full` from `process(exchange, callback)`. ```java from("direct:start") .doTry() .recipientList(constant("seda:work?size=1")) .end() .to("mock:result") .endDoTry() .doCatch(IllegalStateException.class) .to("mock:caught") .end(); // with the queue full, template.sendBody("direct:start", "x") never returns ``` ## The fix When the multicast does not wrap the output in an error handler, it sets `catchProcessorThrows` on the unit of work processor it creates for the output (new public setter `CamelInternalProcessor.setCatchProcessorThrows`). That is the flag CAMEL-26464 added and `DefaultChannel` sets for steps without an error handler, so the same rule applies. A throw before the callback fails the copy through the reactive executor and runs the done work of its unit of work. The multicast then continues exactly once. A throw after the callback was called is rethrown, as before. A plain catch in the sub task would also end the hang, but it skips the copy's unit of work, and it continues the exchange twice when the producer handed its callback to the reactive executor before it threw. The CAMEL-26464 entry of the 4.24 upgrade guide now lists these recipients too (a second call of the callback is ignored and logged at WARN, as for the other steps). camel-seda should set the exception instead of throwing when the queue is full; I will file a separate JIRA for that. This change is still needed for other producers that throw. Main only: it builds on CAMEL-26464, which is not on 4.18.x. ## Tests `RecipientListProducerThrowsInDoTryTest`, 9 tests. A producer that throws (default, `synchronous`, `parallelProcessing`, `parallelProcessing` with a `timeout`, `stopOnException`, `shareUnitOfWork`), one that calls back and then throws, and one that hands its callback to the reactive executor and then throws: each route must end the same way as the route whose producer sets the exception, with as many exchanges done, and the producer must be called once. Plus seda with a full queue, which must reach the `doCatch`. On main 7 of the 9 fail (6 time out; with the timeout, the exchange succeeds without the failure); with the fix all 9 pass (20 runs, 180/180). _Claude Code on behalf of allthingssecurity_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
