Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,8 @@ The `run` command allows running Camel in the background with the `--background`
Therefore, to see and understand what happens then the management commands
cane be used, such as `camel ps`, `camel get`, and `camel log`.

NOTE: Only Camel Main is supported to run in background

[source,bash]
----
$ camel run chuck.yaml --background
Expand Down Expand Up @@ -1802,6 +1804,11 @@ $ camel stop chuck
Shutting down Camel integration (pid: 80093)
----

When running in background, then Camel JBang (**4.10 onwards**) will now automatic wait for the integration
to startup before returning from the CLI command. This ensures that if there are any startup
errors such as compilation errors or DSL errors etc. then these are captured and printed in the shell.
You can use the option `--background-wait=false` to turn this off.

==== Starting and Stopping routes

The `camel cmd` is intended for executing miscellaneous commands in the running Camel integrations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ public File getDebugFile(String pid) {
return new File(CommandLineHelper.getCamelDir(), pid + "-debug.json");
}

public File getRunBackgroundLogFile(String uuid) {
return new File(CommandLineHelper.getCamelDir(), uuid + "-run.log");
}

protected Printer printer() {
var out = getMain().getOut();
CommandHelper.SetPrinter(out);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -59,7 +60,10 @@
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StopWatch;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.json.JsonObject;
import org.apache.camel.util.json.Jsoner;
import org.apache.camel.xml.io.util.XmlStreamDetector;
import org.apache.camel.xml.io.util.XmlStreamInfo;
import picocli.CommandLine;
Expand All @@ -68,6 +72,7 @@
import picocli.CommandLine.Parameters;

import static org.apache.camel.dsl.jbang.core.common.CamelCommandHelper.CAMEL_INSTANCE_TYPE;
import static org.apache.camel.dsl.jbang.core.common.CamelCommandHelper.extractState;
import static org.apache.camel.dsl.jbang.core.common.GistHelper.asGistSingleUrl;
import static org.apache.camel.dsl.jbang.core.common.GistHelper.fetchGistUrls;
import static org.apache.camel.dsl.jbang.core.common.GitHubHelper.asGithubSingleUrl;
Expand Down Expand Up @@ -129,6 +134,10 @@ public class Run extends CamelCommand {
@Option(names = { "--background" }, defaultValue = "false", description = "Run in the background")
public boolean background;

@Option(names = { "--background-wait" }, defaultValue = "true",
description = "To wait for run in background to startup successfully, before returning")
public boolean backgroundWait = true;

@Option(names = { "--empty" }, defaultValue = "false", description = "Run an empty Camel without loading source files")
public boolean empty;

Expand Down Expand Up @@ -896,6 +905,11 @@ protected void addDependencies(String... deps) {
}

protected int runQuarkus() throws Exception {
if (background) {
printer().println("Run Camel Quarkus with --background is not supported");
return 1;
}

// create temp run dir
File runDir = new File(RUN_PLATFORM_DIR, Long.toString(System.currentTimeMillis()));
if (!this.background) {
Expand Down Expand Up @@ -934,14 +948,14 @@ protected int runQuarkus() throws Exception {
eq.ignoreLoadingError = this.ignoreLoadingError;
eq.lazyBean = this.lazyBean;

printer().println("Running using Quarkus v" + eq.quarkusVersion + " (preparing and downloading files)");

// run export
int exit = eq.export();
if (exit != 0 || this.exportRun) {
return exit;
}

System.out.println("Running using Quarkus v" + eq.quarkusVersion + " (preparing and downloading files)");

// run quarkus via maven
String mvnw = "/mvnw";
if (FileUtil.isWindows()) {
Expand All @@ -950,24 +964,19 @@ protected int runQuarkus() throws Exception {
ProcessBuilder pb = new ProcessBuilder();
pb.command(runDir + mvnw, "--quiet", "--file", runDir.toString(), "package", "quarkus:" + (dev ? "dev" : "run"));

if (background) {
Process p = pb.start();
this.spawnPid = p.pid();
if (!exportRun && !transformRun && !transformMessageRun) {
printer().println("Running Camel Quarkus integration: " + name + " (version: " + eq.quarkusVersion
+ ") in background");
}
return 0;
} else {
pb.inheritIO(); // run in foreground (with IO so logs are visible)
Process p = pb.start();
this.spawnPid = p.pid();
// wait for that process to exit as we run in foreground
return p.waitFor();
}
pb.inheritIO(); // run in foreground (with IO so logs are visible)
Process p = pb.start();
this.spawnPid = p.pid();
// wait for that process to exit as we run in foreground
return p.waitFor();
}

protected int runSpringBoot() throws Exception {
if (background) {
printer().println("Run Camel Spring Boot with --background is not supported");
return 1;
}

// create temp run dir
File runDir = new File(RUN_PLATFORM_DIR, Long.toString(System.currentTimeMillis()));
if (!this.background) {
Expand Down Expand Up @@ -1010,14 +1019,14 @@ protected int runSpringBoot() throws Exception {
eq.ignoreLoadingError = this.ignoreLoadingError;
eq.lazyBean = this.lazyBean;

printer().println("Running using Spring Boot v" + eq.springBootVersion + " (preparing and downloading files)");

// run export
int exit = eq.export();
if (exit != 0 || exportRun) {
return exit;
}

System.out.println("Running using Spring Boot v" + eq.springBootVersion + " (preparing and downloading files)");

// prepare spring-boot for logging to file
InputStream is = Run.class.getClassLoader().getResourceAsStream("spring-boot-logback.xml");
eq.safeCopy(is, new File(eq.exportDir + "/src/main/resources/logback.xml"));
Expand All @@ -1030,21 +1039,11 @@ protected int runSpringBoot() throws Exception {
}
pb.command(runDir + mvnw, "--quiet", "--file", runDir.toString(), "spring-boot:run");

if (background) {
Process p = pb.start();
this.spawnPid = p.pid();
if (!exportRun && !transformRun && !transformMessageRun) {
printer().println("Running Camel Spring Boot integration: " + name + " (version: " + camelVersion
+ ") in background");
}
return 0;
} else {
pb.inheritIO(); // run in foreground (with IO so logs are visible)
Process p = pb.start();
this.spawnPid = p.pid();
// wait for that process to exit as we run in foreground
return p.waitFor();
}
pb.inheritIO(); // run in foreground (with IO so logs are visible)
Process p = pb.start();
this.spawnPid = p.pid();
// wait for that process to exit as we run in foreground
return p.waitFor();
}

private boolean acceptPropertiesFile(String file) {
Expand Down Expand Up @@ -1150,6 +1149,7 @@ private Properties doLoadAndInitProfileProperties(File profilePropertiesFile) th
openapi = answer.getProperty("camel.jbang.open-api", openapi);
download = "true".equals(answer.getProperty("camel.jbang.download", download ? "true" : "false"));
background = "true".equals(answer.getProperty("camel.jbang.background", background ? "true" : "false"));
backgroundWait = "true".equals(answer.getProperty("camel.jbang.backgroundWait", backgroundWait ? "true" : "false"));
jvmDebugPort = parseJvmDebugPort(answer.getProperty("camel.jbang.jvmDebug", Integer.toString(jvmDebugPort)));
camelVersion = answer.getProperty("camel.jbang.camel-version", camelVersion);
kameletsVersion = answer.getProperty("camel.jbang.kameletsVersion", kameletsVersion);
Expand Down Expand Up @@ -1201,6 +1201,9 @@ protected int runCamelVersion(KameletMain main) throws Exception {
if (background) {
cmds.remove("--background=true");
cmds.remove("--background");
cmds.remove("--background-wait");
cmds.remove("--background-wait=false");
cmds.remove("--background-wait=true");
}
if (camelVersion != null) {
cmds.remove("--camel-version=" + camelVersion);
Expand Down Expand Up @@ -1236,13 +1239,7 @@ protected int runCamelVersion(KameletMain main) throws Exception {
pb.command(jbangArgs);

if (background) {
Process p = pb.start();
this.spawnPid = p.pid();
if (!exportRun && !transformRun && !transformMessageRun) {
printer().println("Running Camel integration: " + name + " (version: " + camelVersion
+ ") in background with PID: " + p.pid());
}
return 0;
return runBackgroundProcess(pb, "Camel Main");
} else {
pb.inheritIO(); // run in foreground (with IO so logs are visible)
Process p = pb.start();
Expand All @@ -1266,17 +1263,74 @@ protected int runBackground(KameletMain main) throws Exception {

cmds.remove("--background=true");
cmds.remove("--background");
cmds.remove("--background-wait=false");
cmds.remove("--background-wait=true");
cmds.remove("--background-wait");

addCamelCommand(cmds);

ProcessBuilder pb = new ProcessBuilder();
pb.command(cmds);

return runBackgroundProcess(pb, "Camel Main");
}

protected int runBackgroundProcess(ProcessBuilder pb, String kind) throws Exception {
File log = null;
if (backgroundWait) {
// store background output in a log file to capture any error on startup
log = getRunBackgroundLogFile("" + new Random().nextLong());
log.deleteOnExit();
pb.redirectErrorStream(true);
pb.redirectOutput(log);
}

Process p = pb.start();
this.spawnPid = p.pid();
if (!exportRun && !transformRun && !transformMessageRun) {
printer().println("Running Camel integration: " + name + " in background with PID: " + p.pid());
printer().println(
"Running " + kind + ": " + name + " in background with PID: " + p.pid()
+ (backgroundWait ? " (waiting to startup)" : ""));
}

int ec = 0;
if (log != null) {
StopWatch watch = new StopWatch();
int state = 0; // state 5 is running
while (p.isAlive() && watch.taken() < 20000 && state < 5) {
JsonObject root = loadStatus(p.pid());
if (root != null) {
JsonObject context = (JsonObject) root.get("context");
if (context != null) {
state = context.getInteger("phase");
}
}
if (state < 5) {
try {
Thread.sleep(500);
} catch (Exception e) {
// we want to exit
break;
}
}
}
if (!p.isAlive()) {
ec = p.exitValue();
if (ec != 0) {
printer().println(kind + ": " + name + " startup failure");
printer().println("");
String text = IOHelper.loadText(new FileInputStream(log));
printer().print(text);
}
} else {
printer().println(kind + ": " + name + " (state: " + extractState(state) + ")");
}
}
return 0;
if (log != null) {
log.delete();
}

return ec;
}

protected int runDebug(KameletMain main) throws Exception {
Expand Down Expand Up @@ -1335,6 +1389,9 @@ protected int runCustomCamelVersion(KameletMain main) throws Exception {
if (background) {
cmds.remove("--background=true");
cmds.remove("--background");
cmds.remove("--background-wait=true");
cmds.remove("--background-wait=false");
cmds.remove("--background-wait");
}
if (repositories != null) {
if (!VersionHelper.isGE(v, "3.18.1")) {
Expand All @@ -1354,13 +1411,7 @@ protected int runCustomCamelVersion(KameletMain main) throws Exception {
ProcessBuilder pb = new ProcessBuilder();
pb.command(jbangArgs);
if (background) {
Process p = pb.start();
this.spawnPid = p.pid();
if (!exportRun && !transformRun && !transformMessageRun) {
printer().println("Running Camel integration: " + name + " (version: " + camelVersion
+ ") in background with PID: " + p.pid());
}
return 0;
return runBackgroundProcess(pb, "Camel Main");
} else {
pb.inheritIO(); // run in foreground (with IO so logs are visible)
Process p = pb.start();
Expand Down Expand Up @@ -1873,4 +1924,20 @@ protected static void addCamelCommand(List<String> cmds) {
cmds.add(0, "camel");
}
}

private JsonObject loadStatus(long pid) {
try {
File f = getStatusFile(Long.toString(pid));
if (f != null) {
FileInputStream fis = new FileInputStream(f);
String text = IOHelper.loadText(fis);
IOHelper.close(fis);
return (JsonObject) Jsoner.deserialize(text);
}
} catch (Exception e) {
// ignore
}
return null;
}

}