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 905310472c9 CAMEL-22283: camel-jbang - infra stop to be similar to camel stop (#18748) 905310472c9 is described below commit 905310472c96e943951713277c2be51a126fc7d3 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Mon Jul 28 16:45:34 2025 +0200 CAMEL-22283: camel-jbang - infra stop to be similar to camel stop (#18748) * CAMEL-22283: camel-jbang - infra stop to have kill option * CAMEL-22283: camel-jbang - infra stop to be similar to camel stop --- .../dsl/jbang/core/commands/infra/InfraRun.java | 58 +++++++------- .../dsl/jbang/core/commands/infra/InfraStop.java | 89 +++++++++++++++------- .../dsl/jbang/core/commands/infra/InfraTest.java | 2 +- 3 files changed, 94 insertions(+), 55 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java index 713b7b3c64e..a8eda7bd083 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java @@ -165,7 +165,7 @@ public class InfraRun extends InfraBaseCommand { if (testServiceImplementation != null) { prefix = " with implementation " + testServiceImplementation; } - printer().println("Starting service " + testService + prefix); + printer().println("Starting service " + testService + prefix + " (PID: " + RuntimeUtil.getPid() + ")"); } actualService.getClass().getMethod("initialize").invoke(actualService); @@ -207,46 +207,52 @@ public class InfraRun extends InfraBaseCommand { // use shutdown hook as fallback to shut-down and delete files Runtime.getRuntime().addShutdownHook(new Thread(() -> shutdownInfra(closed, logFile, jsonFile, actualService))); + final CountDownLatch latch = new CountDownLatch(1); + // running in foreground then wait for user to exit final Console c = System.console(); if (c != null) { if (!jsonOutput) { printer().println("Press ENTER to stop the execution"); } - boolean quit = false; - do { - String line = c.readLine(); - if (line != null) { - quit = true; - } - } while (!quit); - } else { - final CountDownLatch latch = new CountDownLatch(1); - // headless (running in background so wait until being signalled to stop) Thread t = new Thread(() -> { - while (latch.getCount() > 0) { - try { - Thread.sleep(1000); - } catch (Exception e) { - // ignore - } - File f = jsonFile.toFile(); - if (!f.exists()) { + boolean quit = false; + do { + String line = c.readLine(); + if (line != null) { + quit = true; latch.countDown(); } - } - }, "InfraWait"); + } while (!quit); + }, "WaitEnter"); t.start(); - + } else { // wait for this process to be stopped printer().println("Running (use camel infra stop " + testService + (testServiceImplementation != null ? " " + testServiceImplementation : "") + " to stop the execution)"); - try { - latch.await(); - } catch (Exception e) { - // ignore + } + + // always wait for external signal to stop if the json-file is deleted + Thread t = new Thread(() -> { + while (latch.getCount() > 0) { + try { + Thread.sleep(1000); + } catch (Exception e) { + // ignore + } + File f = jsonFile.toFile(); + if (!f.exists()) { + latch.countDown(); + } } + }, "WaitShutdownSignal"); + t.start(); + + try { + latch.await(); + } catch (Exception e) { + // ignore } shutdownInfra(closed, logFile, jsonFile, actualService); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraStop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraStop.java index 73a4e611794..38b6620731b 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraStop.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraStop.java @@ -16,21 +16,28 @@ */ package org.apache.camel.dsl.jbang.core.commands.infra; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import org.apache.camel.dsl.jbang.core.common.CommandLineHelper; +import org.apache.camel.dsl.jbang.core.common.PathUtils; +import org.apache.camel.support.PatternHelper; import picocli.CommandLine; @CommandLine.Command(name = "stop", - description = "Stop an external service") + description = "Shuts down running infrastructure services", sortOptions = false, showDefaultValues = true) public class InfraStop extends InfraBaseCommand { - @CommandLine.Parameters(description = "Service name", arity = "1") - private List<String> serviceName; + @CommandLine.Parameters(description = "Name or pid of running service(s)", arity = "0..1") + String name = "*"; + + @CommandLine.Option(names = { "--kill" }, + description = "To force killing the process (SIGKILL)") + boolean kill; public InfraStop(CamelJBangMain main) { super(main); @@ -38,35 +45,61 @@ public class InfraStop extends InfraBaseCommand { @Override public Integer doCall() throws Exception { - String serviceToStop = serviceName.get(0); - - boolean serviceStopped = false; - String pid = null; - try { - List<Path> pidFiles = Files.list(CommandLineHelper.getCamelDir()) - .filter(p -> p.getFileName().toString().startsWith("infra-" + serviceToStop + "-")) - .toList(); - - for (Path pidFile : pidFiles) { - String name = pidFile.getFileName().toString(); - pid = name.substring(name.lastIndexOf("-") + 1, name.lastIndexOf('.')); - - Files.deleteIfExists(pidFile); - serviceStopped = true; - break; + + Map<Long, Path> pids = findPids(name); + + // stop by deleting the pid file + for (var entry : pids.entrySet()) { + Path pidFile = entry.getValue(); + if (Files.exists(pidFile)) { + printer().println("Shutting down infrastructure services (PID: " + entry.getKey() + ")"); + PathUtils.deleteFile(pidFile); + } + } + if (kill) { + for (Long pid : pids.keySet()) { + ProcessHandle.of(pid).ifPresent(ph -> { + printer().println("Killing infrastructure service (PID: " + pid + ")"); + ph.destroyForcibly(); + }); } - } catch (IOException e) { - // ignore } - if (!serviceStopped) { - printer().println("No Camel Infrastructure found with name " + serviceToStop); - return 0; + return 0; + } + + private Map<Long, Path> findPids(String name) throws Exception { + Map<Long, Path> pids = new HashMap<>(); + + // we need to know the pids of the running camel integrations + if (!name.matches("\\d+")) { + if (name.endsWith("!")) { + // exclusive this name only + name = name.substring(0, name.length() - 1); + } else if (!name.endsWith("*")) { + // lets be open and match all that starts with this pattern + name = name + "*"; + } } - printer().println("Shutting down service " + serviceToStop + " (PID: " + pid + ")"); - ProcessHandle.of(Long.parseLong(pid)).ifPresent(ProcessHandle::destroy); + final String pattern = name; - return 0; + List<Path> pidFiles = Files.list(CommandLineHelper.getCamelDir()) + .filter(p -> { + var n = p.getFileName().toString(); + return n.startsWith("infra-") && n.endsWith(".json"); + }) + .toList(); + for (Path pidFile : pidFiles) { + String fn = pidFile.getFileName().toString(); + String sn = fn.substring(fn.indexOf("-") + 1, fn.lastIndexOf('-')); + String pid = fn.substring(fn.lastIndexOf("-") + 1, fn.lastIndexOf('.')); + if (pid.equals(pattern) || PatternHelper.matchPattern(sn, pattern)) { + pids.put(Long.valueOf(pid), pidFile); + } + } + + return pids; } + } diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraTest.java index d74bace585a..a3cc24b7af5 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraTest.java +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraTest.java @@ -48,7 +48,7 @@ public class InfraTest extends CamelCommandBaseTest { Awaitility.await().untilAsserted(() -> { List<String> lines = printer.getLines(); - Assertions.assertThat(lines).contains("Starting service ftp"); + Assertions.assertThat(lines).anyMatch(l -> l.startsWith("Starting service ftp")); // because we run headless unit test then you would see this message instead of press ENTER to stop Assertions.assertThat(lines).contains("Running (use camel infra stop ftp to stop the execution)"); });