From a0f13bc0fe0f83ca4ed8607be5c160756cc25414 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 16 Jul 2026 14:25:16 +0000 Subject: [PATCH 1/2] Fix flaky tests (batch 14): BacklogTracerActivityTest, CxfTimeoutTest, QuartzPersistentStoreTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BacklogTracer: Make enabled, standby, and activityEnabled fields volatile to prevent JIT register caching and stale cross-thread reads - CxfTimeoutTest: Increase GreeterImplWithSleep from 2s to 10s to reliably trigger the 100ms ReceiveTimeout under CI load - SpringQuartzPersistentStoreRestartAppChangeOptionsTest: Add @Isolated to prevent JMX MBean name collisions with concurrent test classes SSLContextParametersTest fix dropped — already handled by PR #24734. Co-Authored-By: Claude Opus 4.6 --- .../apache/camel/component/cxf/GreeterImplWithSleep.java | 6 +++++- ...ingQuartzPersistentStoreRestartAppChangeOptionsTest.java | 4 ++++ .../java/org/apache/camel/impl/debugger/BacklogTracer.java | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java b/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java index 0ca0dcfb4a1ec..08fe55c57f04b 100644 --- a/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java +++ b/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java @@ -23,7 +23,11 @@ public class GreeterImplWithSleep extends GreeterImpl { @Override public String greetMe(String hi) { try { - Thread.sleep(2000); + // Sleep well beyond the 100ms ReceiveTimeout configured in + // cxfConduitTimeOutContext.xml to reliably trigger a timeout. + // A 2s sleep was too close under CI load — the HTTP response + // could occasionally beat the timeout timer. + Thread.sleep(10000); } catch (Exception ignore) { } diff --git a/components/camel-quartz/src/test/java/org/apache/camel/component/quartz/SpringQuartzPersistentStoreRestartAppChangeOptionsTest.java b/components/camel-quartz/src/test/java/org/apache/camel/component/quartz/SpringQuartzPersistentStoreRestartAppChangeOptionsTest.java index 5c56dcb29ce17..55b2a562a9702 100644 --- a/components/camel-quartz/src/test/java/org/apache/camel/component/quartz/SpringQuartzPersistentStoreRestartAppChangeOptionsTest.java +++ b/components/camel-quartz/src/test/java/org/apache/camel/component/quartz/SpringQuartzPersistentStoreRestartAppChangeOptionsTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Isolated; import org.quartz.CronTrigger; import org.quartz.Scheduler; import org.quartz.SchedulerException; @@ -37,6 +38,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +// Run in isolation to prevent JMX MBean name collisions with concurrent +// test classes that create CamelContexts with the same management name +@Isolated public class SpringQuartzPersistentStoreRestartAppChangeOptionsTest { private static AbstractXmlApplicationContext db; diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java index 059388f860d5e..309e5b1d297d0 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java @@ -62,8 +62,8 @@ public class BacklogTracer extends ServiceSupport implements org.apache.camel.sp public static final int MAX_BACKLOG_SIZE = 1000; private final CamelContext camelContext; private final Language simple; - private boolean enabled; - private boolean standby; + private volatile boolean enabled; + private volatile boolean standby; private final AtomicLong traceCounter = new AtomicLong(); // use a queue with an upper limit to avoid storing too many messages private final Queue queue = new LinkedBlockingQueue<>(MAX_BACKLOG_SIZE); @@ -87,7 +87,7 @@ public class BacklogTracer extends ServiceSupport implements org.apache.camel.sp private boolean includeExchangeProperties = true; private boolean includeExchangeVariables = true; private boolean includeException = true; - private boolean activityEnabled; + private volatile boolean activityEnabled; private boolean traceRests; private boolean traceTemplates; // a pattern to filter tracing nodes From 918c7b50e35e90d9b9013b39137c7a235fb85986 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 15 Jul 2026 22:47:14 +0000 Subject: [PATCH 2/2] Fix CxfTimeoutTest root cause: use explicit CxfConfigurer for ReceiveTimeout The CxfTimeoutTest was flaky because the 100ms ReceiveTimeout configured via the wildcard http-conduit in cxfConduitTimeOutContext.xml was not always being applied. The JAX-WS server published in @BeforeAll creates a default CXF Bus without the timeout configuration. Under CI load, the client conduit could resolve against this wrong Bus and miss the 100ms timeout entirely, causing the test to receive a successful response instead of the expected HttpTimeoutException. The previous fix (increasing GreeterImplWithSleep from 2s to 10s) would not resolve this because without the 100ms timeout, the effective timeout defaults to 60s (CXF default), and 10s < 60s. Fix: add a TimeoutCxfConfigurer that explicitly sets ReceiveTimeout=100 on each conduit, bypassing Bus-level configuration entirely. Revert GreeterImplWithSleep back to 2s since the sleep duration was never the root cause. Also add a comment on BacklogTracer volatile fields explaining why only enabled, standby, and activityEnabled need volatile (toggled at runtime via JMX) while other boolean fields do not (set during initialization). Co-Authored-By: Claude Opus 4.6 --- .../camel/component/cxf/CxfTimeoutTest.java | 42 +++++++++++++++++-- .../component/cxf/GreeterImplWithSleep.java | 6 +-- .../cxf/cxfConduitTimeOutContext.xml | 11 +++-- .../camel/impl/debugger/BacklogTracer.java | 4 ++ 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/CxfTimeoutTest.java b/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/CxfTimeoutTest.java index 0762cec094262..80256ef456850 100644 --- a/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/CxfTimeoutTest.java +++ b/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/CxfTimeoutTest.java @@ -45,6 +45,13 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +/** + * Tests CXF ReceiveTimeout behavior. The timeout is configured to 100ms in cxfConduitTimeOutContext.xml via a wildcard + * http-conduit. However, the JAX-WS server published in {@code @BeforeAll} creates a default CXF Bus without that + * configuration. Under CI load, the client conduit can sometimes resolve against the wrong Bus and miss the 100ms + * timeout entirely. To make the timeout reliable, each timeout-expecting test method uses {@code TimeoutCxfConfigurer} + * to explicitly set the ReceiveTimeout on the conduit, independent of Bus-level configuration. + */ @Isolated public class CxfTimeoutTest extends CamelSpringTestSupport { @@ -61,17 +68,21 @@ public static void startService() { @Test public void testInvokingJaxWsServerWithBusUriParams() throws Exception { - sendTimeOutMessage("cxf://" + JAXWS_SERVER_ADDRESS + "?serviceClass=org.apache.hello_world_soap_http.Greeter&bus=#cxf"); + sendTimeOutMessage( + "cxf://" + JAXWS_SERVER_ADDRESS + + "?serviceClass=org.apache.hello_world_soap_http.Greeter&bus=#cxf&cxfConfigurer=#timeoutConfigurer"); } @Test public void testInvokingJaxWsServerWithoutBusUriParams() throws Exception { - sendTimeOutMessage("cxf://" + JAXWS_SERVER_ADDRESS + "?serviceClass=org.apache.hello_world_soap_http.Greeter"); + sendTimeOutMessage( + "cxf://" + JAXWS_SERVER_ADDRESS + + "?serviceClass=org.apache.hello_world_soap_http.Greeter&cxfConfigurer=#timeoutConfigurer"); } @Test public void testInvokingJaxWsServerWithCxfEndpoint() throws Exception { - sendTimeOutMessage("cxf://bean:springEndpoint"); + sendTimeOutMessage("cxf://bean:springEndpoint?cxfConfigurer=#timeoutConfigurer"); } @Test @@ -117,6 +128,31 @@ protected AbstractXmlApplicationContext createApplicationContext() { return new ClassPathXmlApplicationContext("org/apache/camel/component/cxf/cxfConduitTimeOutContext.xml"); } + /** + * Explicitly sets the 100ms ReceiveTimeout on the conduit so that the timeout is applied regardless of which CXF + * Bus the conduit was created from. + */ + public static class TimeoutCxfConfigurer implements CxfConfigurer { + + @Override + public void configure(AbstractWSDLBasedEndpointFactory factoryBean) { + // Do nothing here + } + + @Override + public void configureClient(Client client) { + HTTPConduit conduit = (HTTPConduit) client.getConduit(); + HTTPClientPolicy policy = new HTTPClientPolicy(); + policy.setReceiveTimeout(100); + conduit.setClient(policy); + } + + @Override + public void configureServer(Server server) { + // Do nothing here + } + } + public static class MyCxfConfigurer implements CxfConfigurer { @Override diff --git a/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java b/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java index 08fe55c57f04b..0ca0dcfb4a1ec 100644 --- a/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java +++ b/components/camel-cxf/camel-cxf-spring-soap/src/test/java/org/apache/camel/component/cxf/GreeterImplWithSleep.java @@ -23,11 +23,7 @@ public class GreeterImplWithSleep extends GreeterImpl { @Override public String greetMe(String hi) { try { - // Sleep well beyond the 100ms ReceiveTimeout configured in - // cxfConduitTimeOutContext.xml to reliably trigger a timeout. - // A 2s sleep was too close under CI load — the HTTP response - // could occasionally beat the timeout timer. - Thread.sleep(10000); + Thread.sleep(2000); } catch (Exception ignore) { } diff --git a/components/camel-cxf/camel-cxf-spring-soap/src/test/resources/org/apache/camel/component/cxf/cxfConduitTimeOutContext.xml b/components/camel-cxf/camel-cxf-spring-soap/src/test/resources/org/apache/camel/component/cxf/cxfConduitTimeOutContext.xml index 21f3b68fd260c..7e55def1f8d9a 100644 --- a/components/camel-cxf/camel-cxf-spring-soap/src/test/resources/org/apache/camel/component/cxf/cxfConduitTimeOutContext.xml +++ b/components/camel-cxf/camel-cxf-spring-soap/src/test/resources/org/apache/camel/component/cxf/cxfConduitTimeOutContext.xml @@ -46,7 +46,12 @@ - + + + + @@ -58,12 +63,12 @@ - + - + diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java index 309e5b1d297d0..75a3683e3b3de 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/debugger/BacklogTracer.java @@ -62,6 +62,10 @@ public class BacklogTracer extends ServiceSupport implements org.apache.camel.sp public static final int MAX_BACKLOG_SIZE = 1000; private final CamelContext camelContext; private final Language simple; + // These three flags are toggled at runtime via JMX/management APIs while routing + // threads read them in shouldTrace() and traceEvent(). Other boolean fields (removeOnDump, + // bodyIncludeStreams, traceRests, etc.) are set during initialization and do not change + // while routes are processing, so they do not need volatile. private volatile boolean enabled; private volatile boolean standby; private final AtomicLong traceCounter = new AtomicLong();