This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/CAMEL-23862 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 3f5188ee4039473d7cb83331501ff74c67a55a6b Author: Claus Ibsen <[email protected]> AuthorDate: Tue Jun 30 16:08:15 2026 +0200 chore(tui): speed up process discovery by scanning status files instead of all OS processes Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../core/commands/tui/DataRefreshService.java | 16 +++++ .../dsl/jbang/core/commands/tui/TuiHelper.java | 81 ++++++++++++++++------ 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java index 2556eae8eef3..1120c041aa92 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/DataRefreshService.java @@ -50,6 +50,7 @@ import org.apache.camel.util.json.Jsoner; class DataRefreshService { private static final long VANISH_DURATION_MS = 6000; + private static final long LIVENESS_CHECK_INTERVAL_MS = 30_000; private static final int MAX_TRACES = 200; /** @@ -81,6 +82,7 @@ class DataRefreshService { // Cached PID list -- full process scan throttled to every 2 seconds (1 second in burst mode) private volatile List<Long> cachedPids = Collections.emptyList(); private volatile long lastFullScanTime; + private volatile long lastLivenessCheckTime; private volatile long burstModeUntil; final Set<String> stoppingPids = ConcurrentHashMap.newKeySet(); @@ -266,9 +268,23 @@ class DataRefreshService { } } if (!fullScan && ctx.selectedPid != null) { + boolean checkLiveness = now - lastLivenessCheckTime >= LIVENESS_CHECK_INTERVAL_MS; + if (checkLiveness) { + lastLivenessCheckTime = now; + } List<IntegrationInfo> previous = data.get(); for (IntegrationInfo prev : previous) { if (!prev.vanishing && !ctx.selectedPid.equals(prev.pid)) { + if (checkLiveness) { + try { + long pid = Long.parseLong(prev.pid); + if (!ProcessHandle.of(pid).map(ProcessHandle::isAlive).orElse(false)) { + continue; + } + } catch (NumberFormatException e) { + // keep it + } + } infos.add(prev); } } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java index d7335aab1f9e..586d04ec5a0c 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiHelper.java @@ -16,6 +16,7 @@ */ package org.apache.camel.dsl.jbang.core.commands.tui; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -28,6 +29,7 @@ import dev.tamboui.style.Style; import dev.tamboui.text.CharWidth; import dev.tamboui.text.Line; import dev.tamboui.text.Span; +import org.apache.camel.dsl.jbang.core.common.CommandLineHelper; import org.apache.camel.dsl.jbang.core.common.ProcessHelper; import org.apache.camel.support.PatternHelper; import org.apache.camel.util.FileUtil; @@ -43,7 +45,8 @@ final class TuiHelper { } /** - * Find PIDs of running Camel integrations matching the given name pattern. + * Find PIDs of running Camel integrations matching the given name pattern. Scans the {@code ~/.camel/} directory + * for status files rather than iterating all OS processes, which is significantly faster. */ static List<Long> findPids(String name, Function<String, Path> statusFileResolver) { List<Long> pids = new ArrayList<>(); @@ -53,29 +56,65 @@ final class TuiHelper { pattern = pattern + "*"; } final String pat = pattern; - ProcessHandle.allProcesses() - .filter(ph -> ph.pid() != cur) - .forEach(ph -> { - JsonObject root = loadStatus(ph.pid(), statusFileResolver); - if (root != null) { - String pName = ProcessHelper.extractName(root, ph); - pName = FileUtil.onlyName(pName); + + for (long pid : findCandidatePids()) { + if (pid == cur) { + continue; + } + // check process is still alive + if (!ProcessHandle.of(pid).map(ProcessHandle::isAlive).orElse(false)) { + continue; + } + JsonObject root = loadStatus(pid, statusFileResolver); + if (root != null) { + ProcessHandle ph = ProcessHandle.of(pid).orElse(null); + String pName = ProcessHelper.extractName(root, ph); + pName = FileUtil.onlyName(pName); + if (pName != null && !pName.isEmpty() && PatternHelper.matchPattern(pName, pat)) { + pids.add(pid); + } else { + JsonObject context = (JsonObject) root.get("context"); + if (context != null) { + pName = context.getString("name"); + if ("CamelJBang".equals(pName)) { + pName = null; + } if (pName != null && !pName.isEmpty() && PatternHelper.matchPattern(pName, pat)) { - pids.add(ph.pid()); - } else { - JsonObject context = (JsonObject) root.get("context"); - if (context != null) { - pName = context.getString("name"); - if ("CamelJBang".equals(pName)) { - pName = null; - } - if (pName != null && !pName.isEmpty() && PatternHelper.matchPattern(pName, pat)) { - pids.add(ph.pid()); - } - } + pids.add(pid); } } - }); + } + } + } + return pids; + } + + /** + * List candidate PIDs by scanning {@code ~/.camel/} for {@code *-status.json} files. This is O(number of status + * files) rather than O(total OS processes). + */ + static List<Long> findCandidatePids() { + List<Long> pids = new ArrayList<>(); + try { + Path camelDir = CommandLineHelper.getCamelDir(); + if (Files.isDirectory(camelDir)) { + try (var files = Files.list(camelDir)) { + files.forEach(p -> { + String fn = p.getFileName().toString(); + if (fn.endsWith("-status.json")) { + try { + long pid = Long.parseLong(fn.substring(0, fn.length() - "-status.json".length())); + pids.add(pid); + } catch (NumberFormatException e) { + // not a PID-based status file + } + } + }); + } + } + } catch (IOException e) { + // ignore + } return pids; }
