This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 888c217cae62 CAMEL-26754: camel-cluster - ClusteredRoutePolicy: start
a route added after the CamelContext started once the initial delay elapsed
(#29529)
888c217cae62 is described below
commit 888c217cae627a31e19563bd9d4f94e02174137d
Author: allthingssecurity <[email protected]>
AuthorDate: Tue Nov 10 13:28:21 2026 +0530
CAMEL-26754: camel-cluster - ClusteredRoutePolicy: start a route added
after the CamelContext started once the initial delay elapsed (#29529)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../camel/impl/cluster/ClusteredRoutePolicy.java | 8 +++
.../camel/cluster/ClusteredEdgeCasesTest.java | 68 ++++++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git
a/core/camel-cluster/src/main/java/org/apache/camel/impl/cluster/ClusteredRoutePolicy.java
b/core/camel-cluster/src/main/java/org/apache/camel/impl/cluster/ClusteredRoutePolicy.java
index 0e7115d31d60..db96dd245bfd 100644
---
a/core/camel-cluster/src/main/java/org/apache/camel/impl/cluster/ClusteredRoutePolicy.java
+++
b/core/camel-cluster/src/main/java/org/apache/camel/impl/cluster/ClusteredRoutePolicy.java
@@ -198,6 +198,14 @@ public final class ClusteredRoutePolicy extends
RoutePolicySupport implements Ca
this.stoppedRoutes.add(route);
}
+ if (camelContext.isStarted() && initialDelay != null &&
initialDelay.toMillis() > 0) {
+ // A policy attached to a CamelContext that has already started
gets neither the started event nor the
+ // fully started callback, so its initial delay starts now (it
applies only once). This is done here and
+ // not when the CamelContext is set, as the initial delay may be
set after that. Only the timer is
+ // scheduled here: the policy lock is not taken, as the caller may
hold the CamelContext route lock.
+ listener.onCamelContextStarted();
+ }
+
startManagedRoutes();
}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/cluster/ClusteredEdgeCasesTest.java
b/core/camel-core/src/test/java/org/apache/camel/cluster/ClusteredEdgeCasesTest.java
index a2e446327f06..20907a4bc322 100644
---
a/core/camel-core/src/test/java/org/apache/camel/cluster/ClusteredEdgeCasesTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/cluster/ClusteredEdgeCasesTest.java
@@ -68,6 +68,74 @@ public class ClusteredEdgeCasesTest {
}
}
+ @Test
+ public void testInitialDelayForRouteAddedAfterStart() throws Exception {
+ TestClusterService cs = new TestClusterService("cs");
+ CamelContext context = new DefaultCamelContext();
+ context.addService(cs);
+ ClusteredRouteController controller = new ClusteredRouteController();
+ controller.setNamespace("my-ns");
+ controller.setInitialDelay(Duration.ofMillis(300));
+ context.setRouteController(controller);
+ context.start();
+ try {
+ long added = System.nanoTime();
+ // the controller creates the policy of the route, and sets the
initial delay after the CamelContext
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("seda:foo").routeId("foo").to("mock:foo");
+ }
+ });
+ assertEquals(ServiceStatus.Stopped,
context.getRouteController().getRouteStatus("foo"));
+
+ cs.getView().setLeader(true);
+
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(
+ () -> assertEquals(ServiceStatus.Started,
context.getRouteController().getRouteStatus("foo")));
+ // and the initial delay still applies to the route added after
start
+ long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() -
added);
+ assertTrue(elapsed >= 300, "The route started after " + elapsed +
" ms, before the initial delay of 300 ms");
+ } finally {
+ context.stop();
+ }
+ }
+
+ @Test
+ public void testInitialDelayForRouteAddedAfterStartOnLeader() throws
Exception {
+ TestClusterService cs = new TestClusterService("cs");
+ CamelContext context = new DefaultCamelContext();
+ context.addService(cs);
+ context.start();
+ // creates and starts the view of the namespace, so this node is
already the leader when the route is added
+ CamelClusterView view = cs.getView("my-ns");
+ try {
+ cs.getView().setLeader(true);
+
+ ClusteredRoutePolicy policy =
ClusteredRoutePolicy.forNamespace("my-ns");
+ policy.setInitialDelay(Duration.ofMillis(200));
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+
from("seda:foo").routeId("foo").routePolicy(policy).to("mock:foo");
+ }
+ });
+ // the route controller starts the route as usual
+ assertEquals(ServiceStatus.Started,
context.getRouteController().getRouteStatus("foo"));
+
+ // the node loses the leadership, and takes it again later
+ cs.getView().setLeader(false);
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(
+ () -> assertEquals(ServiceStatus.Stopped,
context.getRouteController().getRouteStatus("foo")));
+ cs.getView().setLeader(true);
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(
+ () -> assertEquals(ServiceStatus.Started,
context.getRouteController().getRouteStatus("foo")));
+ } finally {
+ cs.releaseView(view);
+ context.stop();
+ }
+ }
+
@Test
public void testRemovedRouteIdReusedByOtherRoute() throws Exception {
TestClusterService cs = new TestClusterService("cs");