[ 
https://issues.apache.org/jira/browse/CAMEL-24133?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18096806#comment-18096806
 ] 

Claus Ibsen commented on CAMEL-24133:
-------------------------------------

Fixed via https://github.com/apache/camel/pull/24796

> camel-resilience4j / camel-microprofile-fault-tolerance - Circuit Breaker EIP 
> corrupts in-flight exchange in pooled mode (releases original exchange 
> instead of copy)
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24133
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24133
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-microprofile-fault-tolerance, eip
>    Affects Versions: 4.21.0
>            Reporter: Federico Mariani
>            Assignee: Claus Ibsen
>            Priority: Major
>             Fix For: 4.22.0
>
>         Attachments: 
> FaultTolerancePooledProcessorExchangeFactoryIssueTest.java, 
> ResiliencePooledProcessorExchangeFactoryIssueTest.java
>
>
> The Circuit Breaker EIP corrupts in-flight exchanges when exchange pooling is 
> enabled ({{camel.main.exchange-factory=pooled}}). Both implementations 
> release the *original* in-flight exchange back to the processor exchange pool 
> instead of the correlated copy:
> * {{ResilienceProcessor.processTask()}} (camel-resilience4j)
> * {{FaultToleranceProcessor.CircuitBreakerTask.call()}} 
> (camel-microprofile-fault-tolerance)
> {code:java}
> // and release exchange back in pool
> processorExchangeFactory.release(exchange);   // 'exchange' is the ORIGINAL 
> in-flight exchange; 'copy' is leaked
> {code}
> Every other core EIP releases the derived exchange ({{Splitter}} releases 
> {{copy}}, {{Enricher}} releases {{resourceExchange}}, {{MulticastProcessor}} 
> releases {{pair.getExchange()}}).
> {{PooledProcessorExchangeFactory.release()}} calls {{PooledExchange.done()}}, 
> which wipes properties, exception and exchangeId, resets the message, fires 
> the consumer's {{onDone}} hook, and then offers the still-live exchange into 
> the per-processor pool.
> Consequences with pooled mode enabled:
> * the message body and all exchange properties are wiped right after the 
> protected block: downstream steps receive a {{null}} body (both attached 
> reproducers fail with {{Expected: <Bye World> but was: <null>}});
> * the in-flight exchange can be handed out as the "copy" for the next message 
> while the route is still using it, i.e. cross-exchange corruption under 
> concurrency;
> * the correlated copy is never released, so the pool never actually recycles 
> copies.
> Why this was never caught:
> * {{ProducerTemplate}} creates a plain {{DefaultExchange}}, so the 
> {{(PooledExchange)}} cast inside {{release()}} throws {{ClassCastException}}, 
> which {{release()}} silently swallows. The bug is only visible when the 
> exchange comes from a pooled consumer.
> * The existing {{ResiliencePooledRouteOkTest}} sends via ProducerTemplate 
> *and* only installs {{PooledExchangeFactory}}, not 
> {{PooledProcessorExchangeFactory}} (camel-main installs both when 
> {{camel.main.exchange-factory=pooled}}), so it exercises neither half of the 
> bug.
> The attached reproducers use a {{timer:}} consumer plus both pooled 
> factories, i.e. exactly what camel-main configures:
> * {{ResiliencePooledProcessorExchangeFactoryIssueTest.java}} 
> (camel-resilience4j) - FAILS
> * {{FaultTolerancePooledProcessorExchangeFactoryIssueTest.java}} 
> (camel-microprofile-fault-tolerance) - FAILS
> Introduced by CAMEL-16451 (3.x, 2021); affects all of 4.x.
> Suggested fix: release the {{copy}} (when non-null) instead of the original 
> exchange, in both processors.
> _Filed by Claude Code on behalf of Federico Mariani (fmariani)_



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

Reply via email to