shashank created CAMEL-26579:
--------------------------------

             Summary: camel-core - pooled exchanges: releasing the copy a Split 
creates (or a part or enrich resource with shareUnitOfWork) resets the parent's 
unit of work, so its consumer never commits
                 Key: CAMEL-26579
                 URL: https://issues.apache.org/jira/browse/CAMEL-26579
             Project: Camel
          Issue Type: Bug
          Components: camel-core
            Reporter: shashank
            Assignee: shashank


With the pooled exchange factory ({{PooledExchangeFactory}} / 
{{PooledProcessorExchangeFactory}}, deprecated since 4.23 but still supported). 
Related to CAMEL-24800, which made more pooled copies get reset when released.

Releasing a pooled copy resets it ({{DefaultPooledExchange.done()}} -> 
{{resetExtension()}}), and the reset calls {{unitOfWork.reset()}} on the unit 
of work the copy holds. Some copies hold the unit of work of their *parent* 
exchange when they are released, so the release resets the parent's unit of 
work while the parent is still being routed: its synchronizations are cleared 
and the on completions of the parent (the commit or rollback of its consumer, 
such as moving or deleting a file, acknowledging a message; route 
{{onCompletion}}) never run.

Where a released copy holds the parent's unit of work:
# *every Split*: the {{Splitter}} copies the exchange once to create the parts 
from ({{processorExchangeFactory.createCopy}}); a new pooled exchange is 
created with the copy constructor, which copies the unit of work reference, and 
the copy is released when the split is done ({{SplitterIterable.close()}});
# *Split, Multicast and Recipient List with {{shareUnitOfWork}}*: the parts get 
the parent's unit of work ({{prepareSharedUnitOfWork}}) and are released in 
{{MulticastProcessor.doDone}};
# *Enrich with {{shareUnitOfWork}}*: the resource exchange gets the parent's 
unit of work and is released after the aggregation.

The released copy also keeps the reference to that unit of work in the pool. 
And from the second message on, a Split with {{shareUnitOfWork}} takes the copy 
it creates the parts from out of the pool, where it does not hold the parent's 
unit of work, but the parts take the unit of work to share from that copy.

{code:java}
// with PooledExchangeFactory + PooledProcessorExchangeFactory
from("direct:start")
    .process(e -> e.getExchangeExtension().addOnCompletion(commit))   // as a 
consumer registers its commit
    .split(body()).to("mock:part").end()
    .to("mock:result");

template.sendBody("direct:start", List.of("A", "B"));   // commit.onComplete is 
never called
{code}

The same route without the split, or without the pooled factories, calls it 
once. For a file consumer this means the file would not be moved or deleted 
after the route (the commit is such an on completion), so it is picked up again.

Fix idea: before releasing such a copy, detach the parent's unit of work from 
it ({{setUnitOfWork(null)}}), at the three release sites (Splitter copy, 
multicast parts that share it, enrich resource that shares it), and let the 
parts of a Split share the unit of work of the exchange being split rather than 
that of the copy. A copy that has its own unit of work is reset as before.

_Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to