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 cdf2960a6bb7 CAMEL-26606: camel-platform-http-vertx - fail the start 
when the HTTP server cannot bind its port (#29221)
cdf2960a6bb7 is described below

commit cdf2960a6bb7b85763af9d94f2eda07ae9c8b718
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Nov 5 16:48:15 2026 +0100

    CAMEL-26606: camel-platform-http-vertx - fail the start when the HTTP 
server cannot bind its port (#29221)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 .../http/vertx/VertxPlatformHttpServer.java        | 26 ++++++---
 .../VertxPlatformHttpServerPortInUseTest.java      | 67 ++++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  9 +++
 3 files changed, 93 insertions(+), 9 deletions(-)

diff --git 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
index 9a03036a69d6..98d0195f7447 100644
--- 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
+++ 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.platform.http.vertx;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
 
 import io.vertx.core.Handler;
 import io.vertx.core.Vertx;
@@ -29,6 +30,7 @@ import io.vertx.ext.web.Router;
 import io.vertx.ext.web.RoutingContext;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.StaticService;
 import org.apache.camel.api.management.ManagedAttribute;
 import org.apache.camel.api.management.ManagedResource;
@@ -224,6 +226,9 @@ public class VertxPlatformHttpServer extends ServiceSupport 
implements CamelCont
         executor = 
context.getExecutorServiceManager().newSingleThreadExecutor(this, 
"platform-http-service");
         server = vertx.createHttpServer(options);
 
+        // the result of listen is handled on a Vert.x thread: an exception 
thrown there does not reach this thread,
+        // so keep the failure and throw it from here, or the server (and the 
CamelContext) starts with nothing listening
+        AtomicReference<Throwable> failure = new AtomicReference<>();
         CompletableFuture.runAsync(
                 () -> {
                     CountDownLatch latch = new CountDownLatch(1);
@@ -231,16 +236,11 @@ public class VertxPlatformHttpServer extends 
ServiceSupport implements CamelCont
                             .onComplete(result -> {
                                 try {
                                     if (result.failed()) {
-                                        LOGGER.warn("Failed to start Vert.x 
HttpServer on {}:{}, reason: {}",
-                                                configuration.getBindHost(),
-                                                configuration.getBindPort(),
-                                                result.cause().getMessage());
-
-                                        throw new 
RuntimeException(result.cause());
+                                        failure.set(result.cause());
+                                    } else {
+                                        LOGGER.info("Vert.x HttpServer started 
on {}:{}", configuration.getBindHost(),
+                                                server.actualPort());
                                     }
-
-                                    LOGGER.info("Vert.x HttpServer started on 
{}:{}", configuration.getBindHost(),
-                                            server.actualPort());
                                 } finally {
                                     latch.countDown();
                                 }
@@ -254,6 +254,14 @@ public class VertxPlatformHttpServer extends 
ServiceSupport implements CamelCont
                     }
                 },
                 executor).toCompletableFuture().join();
+
+        Throwable cause = failure.get();
+        if (cause != null) {
+            throw new RuntimeCamelException(
+                    "Failed to start Vert.x HttpServer on " + 
configuration.getBindHost() + ":" + configuration.getBindPort()
+                                            + ", reason: " + cause,
+                    cause);
+        }
     }
 
     protected void stopServer() {
diff --git 
a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServerPortInUseTest.java
 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServerPortInUseTest.java
new file mode 100644
index 000000000000..42d28023f2bf
--- /dev/null
+++ 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServerPortInUseTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.platform.http.vertx;
+
+import java.net.BindException;
+import java.net.ServerSocket;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class VertxPlatformHttpServerPortInUseTest {
+    @RegisterExtension
+    AvailablePortFinder.Port port = AvailablePortFinder.find();
+
+    @Test
+    void startFailsWhenPortIsInUse() throws Exception {
+        try (ServerSocket portInUse = new ServerSocket(port.getPort());
+             CamelContext context = new DefaultCamelContext()) {
+            VertxPlatformHttpServerConfiguration configuration = new 
VertxPlatformHttpServerConfiguration();
+            configuration.setBindPort(port.getPort());
+            VertxPlatformHttpServer server = new 
VertxPlatformHttpServer(configuration);
+
+            context.addService(server);
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("platform-http:/test")
+                            .setBody().constant("Hello World");
+                }
+            });
+
+            RuntimeCamelException e = 
assertThrows(RuntimeCamelException.class, context::start);
+            assertInstanceOf(BindException.class, e.getCause());
+            assertTrue(e.getMessage().contains(":" + port.getPort()), 
e.getMessage());
+            assertFalse(context.isStarted());
+
+            // the failed start stopped the server, so it holds neither the 
HTTP server nor its own Vert.x instance
+            assertNull(server.getServer());
+            assertNull(server.getVertx());
+        }
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 0865882254a9..1d16044e4b16 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -3316,6 +3316,15 @@ an `Integer`, `Long`, `Short`, `Float` or `Double` was 
written in its binary for
 now also written in the charset of the response `Content-Type`, as a `String` 
is, rather than in the charset of the
 exchange. To send the binary form of a number, convert the body to `byte[]` 
first.
 
+=== camel-platform-http-vertx - the HTTP server fails to start when it cannot 
listen on its port
+
+The Vert.x HTTP server of platform-http now fails to start when it cannot 
listen on its port, for example because
+another process already uses the port, and so Camel fails to start, with the 
bind error as the cause. This also applies
+to the HTTP server and the HTTP management server of camel-platform-http-main 
(`camel.server.*` and
+`camel.management.*`), which `camel run` uses: a second `camel run` with the 
same `--port` now fails to start. Before,
+the failure was only logged at WARN, and Camel started, with its platform-http 
routes reported as started, although
+nothing listened on the port.
+
 === camel-quickfix - an InOut consumer replies only to application messages, 
and an InOut producer needs CorrelationCriteria
 
 A consumer with `exchangePattern=InOut` now sends a reply only for an 
`AppMessageReceived` event, with the body the

Reply via email to