[
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)