[
https://issues.apache.org/jira/browse/CAMEL-26575?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-26575 started by shashank.
----------------------------------------
> camel-core - Multicast, Split and RecipientList: an AggregationStrategy whose
> onCompletion throws hangs the exchange
> --------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-26575
> URL: https://issues.apache.org/jira/browse/CAMEL-26575
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Reporter: shashank
> Assignee: shashank
> Priority: Minor
>
> Seen while fixing CAMEL-26464.
> {{MulticastTask.doDone}} (and {{doTimeoutDone}}) first sets the done flag
> ({{done.compareAndSet(false, true)}}) and then calls
> {{MulticastProcessor.doDone}}, which calls
> {{AggregationStrategy.onCompletion(subExchange, original)}} before it
> schedules the callback of the exchange
> ({{reactiveExecutor.schedule(callback)}}, its last statement). When
> {{onCompletion}} throws, the callback is never scheduled. The exception goes
> to the catch of {{aggregateCompleted}} (or of {{timeout}}), whose
> {{doFailed}} / {{doTimeoutFailed}} finds the task done already and only logs
> it at DEBUG ({{Exception occurred after the exchange was already
> completed...}}). With {{stopOnException}}, where the multicast is done from
> the callback of the failed sub exchange, it goes up to the reactive executor,
> which logs and drops it. Either way the exchange hangs: a synchronous caller
> ({{template.send}}, a consumer thread, a {{synchronous()}} multicast) blocks
> for good, the exchange stays inflight and a graceful shutdown waits for it.
> A SPIN model of the completion (the aggregator, the callback of a failed sub
> exchange with {{stopOnException}}, and the timeout, all competing for the
> done flag) confirms it: it is not a race, it hangs every time: once
> {{onCompletion}} throws, no interleaving schedules the callback; with the
> change below it is scheduled exactly once in every interleaving.
> {code:java}
> AggregationStrategy strategy = new AggregationStrategy() {
> public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
> return newExchange; }
> public void onCompletion(Exchange exchange, Exchange inputExchange) {
> throw new IllegalStateException("onCompletion"); }
> };
> from("direct:start").multicast(strategy).to("mock:a",
> "mock:b").end().to("mock:result");
> template.send("direct:start", e -> e.getMessage().setBody("Hello")); //
> never returns
> {code}
> On main the send hangs for the multicast (sequential, {{parallelProcessing}},
> {{synchronous}}, {{stopOnException}}, {{timeout}}), the split (also
> {{streaming}}, also in a {{doTry}}: the {{doCatch}} never runs) and the
> recipient list. The same strategy throwing from {{aggregate}} fails the
> exchange with the exception, as expected. {{onCompletion}} is user code (a
> custom strategy, the completion mixin of {{FlexibleAggregationStrategy}}).
> Its javadoc says it must not throw, and none of Camel's own strategies do, so
> this needs a strategy that breaks that contract; it should still fail the
> exchange, as when {{aggregate}} throws, instead of hanging it with only a
> DEBUG log.
> *Proposal*
> * Catch an exception from {{onCompletion}} in {{MulticastProcessor.doDone}},
> do the rest of the done work and schedule the callback as now, with the
> exchange failed with that exception (set after the results are copied, as
> {{ExchangeHelper.copyResults}} would overwrite it) and not marked as
> exhausted, so the error handler of the route handles it (redelivery,
> {{onException}}, dead letter channel) as when the strategy throws from
> {{aggregate}}. An exchange that has failed already (such as with
> {{stopOnException}}) keeps its exception, which tells where it failed, with
> the new one added as suppressed.
> * {{doDone}} runs once per exchange (it is guarded by the done flag), so the
> callback is still scheduled exactly once; nothing changes on the success path.
> * camel-4.18.x has the same bug.
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)