This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/CAMEL-25230 in repository https://gitbox.apache.org/repos/asf/camel.git
commit bf7e4dd77242df581feb742759d666e9309a00c5 Author: Claus Ibsen <[email protected]> AuthorDate: Thu Oct 1 16:01:13 2026 +0200 CAMEL-25230: camel-cli-connector - the connector thread keeps the JVM alive when the application fails to start Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 6 ++++++ .../camel/cli/connector/FileCliConnectorTransport.java | 8 ++++++-- .../cli/connector/LocalCliConnectorFileTransportTest.java | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc index c506d4e1fe6e..84a3776b0714 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc @@ -4097,3 +4097,9 @@ only just modified for the next scan, so a save still being written is not reloa The ~/.camel file handling moved from `LocalCliConnector` to the new `FileCliConnectorTransport`, so the protected `task()`, `actionTask()`, `statusTask()` and `traceTask()` methods were removed from `LocalCliConnector`. Subclasses that only override `sigterm()` are not affected. + +The thread of the file transport (`LocalCliConnector` in its name) is now a daemon thread, as the threads of the +WebSocket transport already were. Before, it kept the JVM alive when the application failed to start, for example a +Spring Boot application whose port was in use: Camel had not started, so it never stopped the connector. An application +that only kept running because of this thread now exits; keep it running on purpose, for example with +`camel.main.run-controller=true` for a Spring Boot application without a web server. diff --git a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/FileCliConnectorTransport.java b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/FileCliConnectorTransport.java index c5e1a3aec8f2..7d51bc62a059 100644 --- a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/FileCliConnectorTransport.java +++ b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/FileCliConnectorTransport.java @@ -82,10 +82,14 @@ public class FileCliConnectorTransport extends ServiceSupport implements CliConn terminating.set(false); // create thread from JDK so it is not managed by Camel because we want the pool to be independent when - // camel is being stopped which otherwise can lead to stopping the thread pool while the task is running + // camel is being stopped which otherwise can lead to stopping the thread pool while the task is running. + // a daemon thread: the connector starts before Camel, so when the application fails to start (Spring Boot + // APPLICATION FAILED TO START) Camel never stops it, and it must not keep the JVM alive (CAMEL-25230) executor = Executors.newSingleThreadScheduledExecutor(r -> { String threadName = ThreadHelper.resolveThreadName(null, "LocalCliConnector"); - return new Thread(r, threadName); + Thread thread = new Thread(r, threadName); + thread.setDaemon(true); + return thread; }); // make it go faster in debug mode diff --git a/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorFileTransportTest.java b/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorFileTransportTest.java index f5ff11126751..81d387323037 100644 --- a/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorFileTransportTest.java +++ b/dsl/camel-cli-connector/src/test/java/org/apache/camel/cli/connector/LocalCliConnectorFileTransportTest.java @@ -120,6 +120,21 @@ class LocalCliConnectorFileTransportTest extends CamelTestSupport { } } + @Test + void theConnectorDoesNotKeepTheJvmAlive() throws Exception { + // started before Camel, it is not stopped when the application fails to start (CAMEL-25230). Started from a + // non-daemon thread, as the main thread of Spring Boot: a new thread takes the daemon flag of its creator + Thread main = new Thread(this::startConnector, "main"); + main.setDaemon(false); + main.start(); + main.join(10_000); + + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> assertThat(Thread.getAllStackTraces().keySet()) + .filteredOn(t -> t.getName().contains("LocalCliConnector")) + .isNotEmpty() + .allMatch(Thread::isDaemon)); + } + @Test void writesStatusSnapshot() { startConnector();
