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

Work on CAMEL-26576 started by shashank.
----------------------------------------
> camel-core - Split/Multicast with shareUnitOfWork: a part sent to seda takes 
> the consumer's commit, which then runs with the outcome of the seda copy
> -----------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-26576
>                 URL: https://issues.apache.org/jira/browse/CAMEL-26576
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-core
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>
> Found while modelling the shared unit of work of a parallel Split (see the 
> linked handover race), then reproduced with deterministic tests on the real 
> classes. It does not need parallel processing.
> Since Camel 4.14 (CAMEL-22259) the parts of a Split, Multicast or Recipient 
> List with {{shareUnitOfWork}} use the parent's unit of work 
> ({{MulticastProcessor.prepareSharedUnitOfWork}}). The 4.14 upgrade guide says 
> the on completions of the parts now run "when the parent UnitOfWork is 
> complete", and the Split docs describe {{shareUnitOfWork}} as a way to treat 
> the whole message as one unit that either succeeds or fails.
> But a part that sends to an endpoint which routes a copy on its own hands 
> over the on completions of its unit of work to that copy, for example 
> {{seda}} with an {{InOnly}} exchange ({{SedaProducer.addToQueue}} -> 
> {{ExchangeHelper.createCorrelatedCopy(exchange, true, true)}} -> 
> {{AbstractExchange.handoverCompletions}} -> 
> {{DefaultUnitOfWork.handoverSynchronization}}). With the shared unit of work 
> that is all the on completions of the parent exchange, including the commit 
> or rollback of its consumer ({{GenericFileOnCompletion}}, the SQS delete, 
> ...). They then run when that seda copy is done, with the outcome of the 
> copy, not of the split:
> * a later part fails the split, but the seda copy succeeds: the consumer 
> commits. The file is moved to the done folder (not to {{moveFailed}}), an SQS 
> message is deleted, so the failed message is not retried;
> * the split succeeds, but the seda copy fails: the consumer rolls back (the 
> file goes to {{moveFailed}}, the SQS message is redelivered and all the parts 
> run again);
> * the commit can run before the split has even finished.
> Before 4.14 each part had its own unit of work, so a part handed over only 
> its own on completions. A part routed into a {{Resequencer}} or 
> {{StreamResequencer}} hands over the same way. (The resource exchange of 
> {{enrich}} with {{shareUnitOfWork}} has always shared the unit of work of the 
> exchange, and can hand over its on completions to a seda copy too, for 
> example with {{waitForTaskToComplete=Never}}; that is older and not part of 
> this.)
> {code:java}
> from("file:inbox?move=done&moveFailed=failed")
>     .split(body().tokenize(",")).shareUnitOfWork()
>         .choice()
>             .when(body().startsWith("a")).to("seda:lines")
>             .when(body().isEqualTo("bad")).throwException(new 
> IllegalArgumentException("bad line"))
>         .end()
>     .end();
> from("seda:lines").to("log:line");
> {code}
> A file with {{a,bad}} fails the split, but ends up in {{done}}, not in 
> {{failed}}.
> On main (1b12eea, 2026-11-02), tests with that route, a Split, a Multicast, a 
> Recipient List and a nested Split fail: the consumer on completion runs once, 
> as {{onComplete}} for the seda copy instead of {{onFailure}} for the failed 
> split exchange; and when only the seda copy fails, {{onFailure}} runs instead 
> of {{onComplete}}. The same routes without the seda part, a plain 
> {{to("seda:...")}} without a split (handover as designed, see CAMEL-9291), 
> and a split where all parts succeed behave as expected.
> Related: CAMEL-22259 (the shared unit of work, 4.14), CAMEL-9291 (handover to 
> seda from a plain route is by design), CAMEL-25094 (the stream cache of a 
> seda copy sent from a Split/Multicast). Affects 4.14.0 and later.
> *Proposal*
> * A part that shares the unit of work of the parent exchange 
> ({{prepareSharedUnitOfWork}}) hands over only the on completions it added to 
> its own exchange, as before 4.14. The on completions of the parent (such as 
> its consumer's commit) stay with the parent and run when the split is done, 
> with its outcome. On completions added to the unit of work directly (such as 
> by a route {{onCompletion}}) stay with the parent too.
> * A new {{ExchangeExtension.setSharedUnitOfWork(UnitOfWork)}} (default: 
> {{setUnitOfWork}}) marks the exchange; it remembers the on completions it 
> adds while it uses that unit of work and hands over only those 
> ({{UnitOfWork.handoverSynchronization(target, filter)}}). A plain InOnly send 
> to seda outside a split is unchanged.
> * Upgrade guide entry: the consumer now commits when the split is done, 
> possibly before the seda copies are processed, so a copy that still reads the 
> input (such as a file body not loaded yet) must load it first or wait for the 
> copy ({{waitForTaskToComplete=Always}}).
> * Target main. A backport to 4.18.x (and 4.14.x) is possible as is (the 
> method is a default method on the internal {{ExchangeExtension}}), but it 
> changes when the consumer commits, so that is the committers' call.
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to