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

commit f7c000e561f83ff67156803f89779826fe8334be
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Jul 10 16:25:38 2026 +0200

    TUI: Add timeouts to blocking I/O on event/render thread
    
    - LaunchManager/DoctorPopup: Use bounded waitFor(5s) + destroyForcibly for 
container runtime checks
    - DocHelper: Use HttpURLConnection with connect/read timeouts instead of 
URL.openStream
    - EndpointsTab: Cache catalog load failures to prevent retry-every-frame 
when offline
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/DocHelper.java     | 12 ++++++++--
 .../dsl/jbang/core/commands/tui/DoctorPopup.java   |  9 ++++++--
 .../dsl/jbang/core/commands/tui/EndpointsTab.java  | 27 +++++++++++++++++-----
 .../dsl/jbang/core/commands/tui/LaunchManager.java |  9 ++++++--
 4 files changed, 45 insertions(+), 12 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
index 009dcf92dcf3..53335ecdd091 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DocHelper.java
@@ -18,6 +18,7 @@ package org.apache.camel.dsl.jbang.core.commands.tui;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.HttpURLConnection;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
 
@@ -40,8 +41,15 @@ final class DocHelper {
     }
 
     static String downloadContent(String url) {
-        try (InputStream is = URI.create(url).toURL().openStream()) {
-            return new String(is.readAllBytes(), StandardCharsets.UTF_8);
+        try {
+            HttpURLConnection conn = (HttpURLConnection) 
URI.create(url).toURL().openConnection();
+            conn.setConnectTimeout(5000);
+            conn.setReadTimeout(10000);
+            try (InputStream is = conn.getInputStream()) {
+                return new String(is.readAllBytes(), StandardCharsets.UTF_8);
+            } finally {
+                conn.disconnect();
+            }
         } catch (Exception e) {
             return null;
         }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
index 90d6fe509171..d0c4f3d43c35 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DoctorPopup.java
@@ -22,6 +22,7 @@ import java.net.ServerSocket;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
 
 import dev.tamboui.layout.Rect;
@@ -217,8 +218,12 @@ class DoctorPopup {
                         .redirectErrorStream(true)
                         .start();
                 p.getInputStream().transferTo(OutputStream.nullOutputStream());
-                int exit = p.waitFor();
-                if (exit == 0) {
+                boolean done = p.waitFor(5, TimeUnit.SECONDS);
+                if (!done) {
+                    p.destroyForcibly();
+                    continue;
+                }
+                if (p.exitValue() == 0) {
                     String name = Character.toUpperCase(cmd.charAt(0)) + 
cmd.substring(1);
                     result.add(Line.from(
                             Span.raw(TuiIcons.indent(TuiIcons.DOCKER)),
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
index e254dc1681a1..cea37c2025fd 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EndpointsTab.java
@@ -19,11 +19,13 @@ package org.apache.camel.dsl.jbang.core.commands.tui;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 import dev.tamboui.layout.Constraint;
 import dev.tamboui.layout.Layout;
@@ -88,6 +90,7 @@ class EndpointsTab extends AbstractTableTab {
     private final DragSplit hSplit = new DragSplit();
 
     private final Map<String, CamelCatalog> catalogCache = new HashMap<>();
+    private final Set<String> catalogLoadFailed = new HashSet<>();
 
     EndpointsTab(MonitorContext ctx, MetricsCollector metrics) {
         super(ctx, "component", "route", "dir", "total", "body", "hdr", "uri");
@@ -824,13 +827,25 @@ class EndpointsTab extends AbstractTableTab {
         if (version == null) {
             return null;
         }
-        return catalogCache.computeIfAbsent(version, v -> {
-            try {
-                return CatalogLoader.loadCatalog(null, v, true);
-            } catch (Exception e) {
-                return null;
+        CamelCatalog cached = catalogCache.get(version);
+        if (cached != null) {
+            return cached;
+        }
+        if (catalogLoadFailed.contains(version)) {
+            return null;
+        }
+        try {
+            cached = CatalogLoader.loadCatalog(null, version, true);
+            if (cached != null) {
+                catalogCache.put(version, cached);
+            } else {
+                catalogLoadFailed.add(version);
             }
-        });
+            return cached;
+        } catch (Exception e) {
+            catalogLoadFailed.add(version);
+            return null;
+        }
     }
 
     private static long unbox(Long value) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
index 5ec6d2df7c39..fcc62fc54c67 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/LaunchManager.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
@@ -137,8 +138,12 @@ class LaunchManager {
                         .redirectErrorStream(true)
                         .start();
                 p.getInputStream().transferTo(OutputStream.nullOutputStream());
-                int exit = p.waitFor();
-                if (exit == 0) {
+                boolean done = p.waitFor(5, TimeUnit.SECONDS);
+                if (!done) {
+                    p.destroyForcibly();
+                    continue;
+                }
+                if (p.exitValue() == 0) {
                     return true;
                 }
             } catch (Exception e) {

Reply via email to