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 81626da27948 CAMEL-26755: camel-support - AbstractCamelClusterService:
give the view reference back when the view fails to start (#29530)
81626da27948 is described below
commit 81626da27948d5540ba7cd2acd9427fd512e23c9
Author: allthingssecurity <[email protected]>
AuthorDate: Tue Nov 10 13:28:11 2026 +0530
CAMEL-26755: camel-support - AbstractCamelClusterService: give the view
reference back when the view fails to start (#29530)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../camel/cluster/ClusterServiceViewTest.java | 34 ++++++++++++++++++++++
.../cluster/AbstractCamelClusterService.java | 14 ++++++++-
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git
a/core/camel-core/src/test/java/org/apache/camel/cluster/ClusterServiceViewTest.java
b/core/camel-core/src/test/java/org/apache/camel/cluster/ClusterServiceViewTest.java
index ea890dad9f18..08401d6ef177 100644
---
a/core/camel-core/src/test/java/org/apache/camel/cluster/ClusterServiceViewTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/cluster/ClusterServiceViewTest.java
@@ -25,6 +25,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import org.apache.camel.ServiceStatus;
@@ -94,6 +95,34 @@ public class ClusterServiceViewTest {
assertEquals(ServiceStatus.Stopped, newView2.getStatus());
}
+ @Test
+ public void testViewReferencesWhenStartFails() throws Exception {
+ TestClusterService service = new
TestClusterService(UUID.randomUUID().toString());
+ service.start();
+
+ // the view cannot be started the first time, for example when the
backend is not reachable yet
+ service.failedStarts.set(1);
+ Throwable failure = assertThrows(RuntimeException.class, () ->
service.getView("ns1"));
+ while (failure != null && !(failure instanceof IllegalStateException))
{
+ failure = failure.getCause();
+ }
+ assertNotNull(failure, "The failure of the view start must be thrown
to the caller");
+
+ // the next user starts the view
+ TestClusterView view =
service.getView("ns1").unwrap(TestClusterView.class);
+ assertEquals(ServiceStatus.Started, view.getStatus());
+
+ // and the view is stopped once its only user has released it
+ service.releaseView(view);
+ assertEquals(ServiceStatus.Stopped, view.getStatus());
+
+ // a restart of the service does not start the view nobody uses
+ service.stop();
+ service.start();
+ assertEquals(ServiceStatus.Stopped, view.getStatus());
+ service.stop();
+ }
+
@Test
public void testViewForceOperations() throws Exception {
TestClusterService service = new
TestClusterService(UUID.randomUUID().toString());
@@ -212,6 +241,9 @@ public class ClusterServiceViewTest {
@Override
protected void doStart() {
+ if (((TestClusterService)
getClusterService()).failedStarts.getAndUpdate(n -> Math.max(0, n - 1)) > 0) {
+ throw new IllegalStateException("Simulated failure to start
view " + getNamespace());
+ }
}
@Override
@@ -232,6 +264,8 @@ public class ClusterServiceViewTest {
}
private static class TestClusterService extends
AbstractCamelClusterService<TestClusterView> {
+ private final AtomicInteger failedStarts = new AtomicInteger();
+
public TestClusterService(String id) {
super(id);
}
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/cluster/AbstractCamelClusterService.java
b/core/camel-support/src/main/java/org/apache/camel/support/cluster/AbstractCamelClusterService.java
index 81b495fb0b0d..753e92236ad0 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/cluster/AbstractCamelClusterService.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/cluster/AbstractCamelClusterService.java
@@ -302,7 +302,19 @@ public abstract class AbstractCamelClusterService<T
extends CamelClusterView> ex
V retain() {
LOG.debug("Retain view {}, old-refs={}", view.getNamespace(),
count.get());
- count.retain();
+ try {
+ count.retain();
+ } catch (RuntimeException e) {
+ // The view could not be started, so the caller gets no
reference: give it back, so the next caller
+ // starts the view again instead of getting a view that is
never started, and a restart of the
+ // service does not start a view that nobody uses.
+ try {
+ count.release();
+ } catch (RuntimeException e2) {
+ e.addSuppressed(e2);
+ }
+ throw e;
+ }
return get();
}