Federico Mariani created CAMEL-24800:
----------------------------------------

             Summary: camel-core - pooled exchange copies share the parent's 
clock, so Splitter children are returned to the pool without reset 
(properties/variables leak between messages)
                 Key: CAMEL-24800
                 URL: https://issues.apache.org/jira/browse/CAMEL-24800
             Project: Camel
          Issue Type: Bug
          Components: camel-core
    Affects Versions: 4.22.0
            Reporter: Federico Mariani
         Attachments: PooledExchangeSplitLeakTest.java

When exchange pooling is enabled ({{PooledExchangeFactory}} + 
{{PooledProcessorExchangeFactory}}), the Splitter's child exchanges are 
returned to the pool *without being reset*, so exchange properties and 
exchange-scoped variables set while processing one message leak into the 
children of the next message that goes through the same split.

*Cause*: {{DefaultPooledExchange(Exchange parent)}} reuses the parent's 
{{ResetableClock}} instance when the parent already has one (since CAMEL-20225, 
4.4):
{code:java}
if (parentClock instanceof ResetableClock rs) {
    this.clock = rs;          // shared with the parent
} else {
    this.clock = new ResetableClock(parent.getClock());
}
{code}
The Splitter creates every child via {{createCorrelatedCopy}} from its (pooled) 
working copy, so parent and child share one clock. On completion the working 
copy is released first: its {{done()}} calls {{clock.unset()}} (created = 0). 
The child's {{done()}} then hits the guard {{if (clock.getCreated() > 0)}} and 
skips the whole reset (properties, variables, extension flags, message), and 
the dirty exchange is offered back to the pool.

*Reproducer* (attached as a unit test): pooled factories, 
{{from("direct:start").split(body()).process(...).to("mock:split")}}; the child 
of the first message sets an exchange property and a variable; the child of the 
second message must not see them, but sees both ({{leakProp=from-first}}, 
{{leak=from-first}}). Headers do not leak because reuse overwrites the message.

*Fix*: give every pooled copy its own clock ({{new 
ResetableClock(parentClock)}} unconditionally). Verified: the reproducer passes 
with that change. Not a regression of a specific release; present since 4.4.

_Claude Code on behalf of Federico Mariani_




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to