Federico Mariani created CAMEL-24179:
----------------------------------------

             Summary: camel-cxf/camel-cxfrs - continuation timeout races with 
in-flight async processing (UoW closed twice, continuation double-resumed)
                 Key: CAMEL-24179
                 URL: https://issues.apache.org/jira/browse/CAMEL-24179
             Project: Camel
          Issue Type: Bug
          Components: camel-cxf
            Reporter: Federico Mariani
            Assignee: Federico Mariani


*Severity:* High

Affects both the SOAP consumer ({{CxfConsumer}}) and the cxfrs invoker 
({{CxfRsInvoker}}), which share the same continuation/async structure.

h3. Problem 1 - timeout mutates and closes an Exchange still being processed
In {{asyncInvoke}}, the new-request branch calls {{createUoW}}, 
{{continuation.suspend(continuationTimeout)}} (default 30000 ms) and then 
{{getAsyncProcessor().process(camelExchange, callback)}}. If the route runs 
longer than the timeout, CXF resumes and the timeout branch runs:
{code:java}
camelExchange = (Exchange) continuation.getObject();
camelExchange.setException(new ExchangeTimedOutException(camelExchange, 
endpoint.getContinuationTimeout()));
return returnResponse(cxfExchange, camelExchange);  // -> doneUoW(camelExchange)
{code}
This mutates ({{setException}}) and closes the UnitOfWork ({{doneUoW}}) of the 
*same* {{camelExchange}} the worker thread is still processing. Nothing 
synchronizes the two threads on Exchange state ({{synchronized(continuation)}} 
guards only the continuation). With pooled exchanges (the modern default), 
{{doneUoW}} can reset/recycle the Exchange while the worker still holds it -> 
cross-request state corruption under load.

h3. Problem 2 - unconditional resume after timeout
The async {{done()}} callback always calls {{continuation.resume()}} with no 
{{isResumed()}}/{{isTimeout()}} guard. After a timeout already produced a 
response and closed the UoW, the late completion resumes again; CXF re-invokes, 
{{returnResponse}}/{{doneUoW}} run a second time ({{uow.done()}} is not 
idempotent), potentially writing a second response onto an already-completed 
servlet response.

h3. Location
{{camel-cxf-rest/.../jaxrs/CxfRsInvoker.java}} ~100-133 and 
{{camel-cxf-soap/.../jaxws/CxfConsumer.java}} ~198-230.

h3. Fix
Redesign timeout-vs-callback completion so exactly one of {timeout, normal 
completion} owns writing the response and closing the UoW:
* on timeout, do not mutate/close the in-flight Exchange; mark the continuation 
abandoned and let the async {{done()}} close the UoW once;
* guard {{done()}} to resume only when the continuation is still pending 
({{!continuation.isResumed() && !continuation.isTimeout()}}).

h3. Reproduction
Set {{continuationTimeout}} low (e.g. 500 ms) and a route with a {{delay}} 
longer than that; assert a single response, a single UoW completion, and no 
state bleed onto a subsequently-pooled exchange. (Timing-sensitive; the two 
problems are one coupled fix.)

----
_Filed by Claude Code (Claude Fable) on behalf of Federico Mariani (GitHub: 
Croway). Findings from an AI-assisted code review of the camel-cxf component 
family; each item was verified against the current source and git history. 
Items marked *[reproducer attached]* include a failing JUnit test that 
demonstrates the defect._



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

Reply via email to