Aurélien Pupier created CAMEL-26696:
---------------------------------------

             Summary: camel-cxf: async producer may never complete the exchange 
when the connection fails
                 Key: CAMEL-26696
                 URL: https://issues.apache.org/jira/browse/CAMEL-26696
             Project: Camel
          Issue Type: Bug
          Components: camel-cxf
    Affects Versions: 4.24.0
            Reporter: Aurélien Pupier


When a cxf:// producer (default, non-synchronous) calls an endpoint where the 
connection fails, such as a closed port, the Camel exchange sometimes never 
completes. The calling thread then waits on the 
DefaultAsyncProcessorAwaitManager latch indefinitely. A route calling a SOAP 
service that is down could hang instead of failing with an exception.

This was observed as a flaky test, CxfProducerTest.testInvokingAWrongServer 
(CAMEL-26600). It hits the 30s @Timeout even after connection and receive 
timeouts were configured on the HTTP conduit (PR #29219). Thread dump of the 
stuck test thread:

java.util.concurrent.TimeoutException: testInvokingAWrongServer() timed out 
after 30 seconds
Caused by: ...ExecutionTimeoutException: Execution timed out in thread 
junit-timeout-thread-10
        at 
java.base/java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230)
        at 
org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.await(DefaultAsyncProcessorAwaitManager.java:112)
        at 
org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:89)
        at 
org.apache.camel.impl.engine.SharedCamelInternalProcessor.process(SharedCamelInternalProcessor.java:86)
        at 
org.apache.camel.support.cache.DefaultProducerCache.send(DefaultProducerCache.java:177)
        at 
org.apache.camel.impl.engine.DefaultProducerTemplate.request(DefaultProducerTemplate.java:372)
        at 
org.apache.camel.component.cxf.jaxws.CxfProducerTest.sendSimpleMessageWithPayloadMessage(CxfProducerTest.java:276)
        at 
org.apache.camel.component.cxf.jaxws.CxfProducerTest.testInvokingAWrongServer(CxfProducerTest.java:201)

The test thread is parked in the await manager. So the exchange went through 
CxfProducer.process(Exchange, AsyncCallback), which returned false, and 
AsyncCallback.done(...) was never called.

Analysis so far (not confirmed)

The async path completes the exchange only through 
CxfClientCallback.handleResponse or handleException calling 
camelAsyncCallback.done(false). Possible causes:

CXF's HTTPConduit or async client never invokes ClientCallback.handleException 
for some connection failures. This might be a CXF bug, or a missing timeout or 
executor configuration.

handleException is invoked, but code before camelAsyncCallback.done(false) in 
the finally block throws, so the callback is skipped. Candidates in 
CxfClientCallback:

endpoint.getCookieHandler().storeCookies(...) (only IOException is caught).
endpoint.getCxfBinding().populateExchangeFromCxfResponse(...).
conduitSelector.complete(cxfExchange).
Wrapping the Camel callback in its own try/finally would make this robust.

A race or thread issue in the CXF async client when the failure happens very 
quickly.

The flakiness increased around 2 Nov. The camel-cxf changes of that day 
(CAMEL-26143, CAMEL-26144) don't touch the async callback, so they don't seem 
to be the cause. A CXF or JDK change, or the CI environment, may be involved.

Current workaround

PR #29339 sets synchronous=true on the "wrong server" endpoint of 
CxfProducerTest. The test is stable, but the async error path is no longer 
covered by any test.

Expected behavior

When the connection to the target fails, the exchange completes with an 
exception. The error is reported via the callback, and the thread never waits 
indefinitely.

Suggested next steps

Reproduce outside the flaky test, for example by looping a producer call to a 
closed port with the default async mode.
Log or debug whether CxfClientCallback.handleException is reached and whether 
done() is called.
Make CxfClientCallback always call camelAsyncCallback.done(false), even if the 
preceding steps throw.
If the cause is in CXF, report it upstream or add a safe configuration or 
timeout.
Add a test covering the async path with a failing connection, then remove the 
synchronous=true workaround from CxfProducerTest.
Drafted by IBM Bob on behalf of apupier.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to