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)