com.danielflower.apprunner.runners.ProcessStarter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of app-runner Show documentation
Show all versions of app-runner Show documentation
A self-hosted platform-as-a-service that hosts web apps written in Java, Clojure, NodeJS, Python, golang and Scala.
package com.danielflower.apprunner.runners;
import com.danielflower.apprunner.io.LineConsumer;
import com.danielflower.apprunner.io.WriterToOutputBridge;
import com.danielflower.apprunner.problems.ProjectCannotStartException;
import org.apache.commons.exec.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.jetty.io.WriterOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import static com.danielflower.apprunner.FileSandbox.fullPath;
public class ProcessStarter {
public static final Logger log = LoggerFactory.getLogger(ProcessStarter.class);
public static Killer startDaemon(LineConsumer buildLogHandler, LineConsumer consoleLogHandler, Map envVarsForApp, CommandLine command, File projectRoot, Waiter startupWaiter) {
long startTime = logStartInfo(command, projectRoot);
Killer watchDog = new Killer(ExecuteWatchdog.INFINITE_TIMEOUT, command);
Executor executor = createExecutor(consoleLogHandler, command, projectRoot, watchDog);
boolean started = false;
try {
DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
executor.execute(command, envVarsForApp, handler);
startupWaiter.or(c -> handler.hasResult()); // stop waiting if the process exist
startupWaiter.blockUntilReady();
if (handler.hasResult()) {
String message = "The project at " + fullPath(projectRoot) + " started but exited all too soon. Check the console log for information.";
buildLogHandler.consumeLine(message);
throw new ProjectCannotStartException(message);
} else {
started = true;
}
} catch (TimeoutException te) {
String message = "Built successfully, but timed out waiting for startup at " + fullPath(projectRoot)
+ " - is the application responding to HTTP requests on the port specified by the APP_PORT " +
"environment variable (currently " + envVarsForApp.get("APP_PORT") + ")?";
buildLogHandler.consumeLine(message);
throw new ProjectCannotStartException(message);
} catch (ProjectCannotStartException pcse) {
throw pcse;
} catch (Exception e) {
String message = "Built successfully, but error on start for " + fullPath(projectRoot);
buildLogHandler.consumeLine(message);
buildLogHandler.consumeLine(e.toString());
throw new ProjectCannotStartException(message, e);
} finally {
if (!started) {
watchDog.destroyProcess();
}
}
logEndTime(command, startTime);
return watchDog;
}
public static void run(LineConsumer outputHandler, Map envVarsForApp, CommandLine command, File projectRoot, long timeout) throws ProjectCannotStartException {
long startTime = logStartInfo(command, projectRoot);
ExecuteWatchdog watchDog = new ExecuteWatchdog(timeout);
Executor executor = createExecutor(outputHandler, command, projectRoot, watchDog);
try {
int exitValue = executor.execute(command, envVarsForApp);
if (executor.isFailure(exitValue)) {
String message = watchDog.killedProcess()
? "Timed out waiting for " + command
: "Exit code " + exitValue + " returned from " + command;
throw new ProjectCannotStartException(message);
}
} catch (Exception e) {
String message = "Error running: " + fullPath(projectRoot) + "> " + StringUtils.join(command.toStrings(), " ");
outputHandler.consumeLine(message);
outputHandler.consumeLine(e.toString());
throw new ProjectCannotStartException(message, e);
}
logEndTime(command, startTime);
}
public static Pair run(CommandLine command) {
ExecuteWatchdog watchDog = new ExecuteWatchdog(30000);
StringBuilder output = new StringBuilder();
Executor executor = createExecutor(output::append, command, new File("."), watchDog);
output.setLength(0);
try {
int exitValue = executor.execute(command);
if (executor.isFailure(exitValue)) {
return Pair.of(false, "Not available");
}
} catch (Exception e) {
return Pair.of(false, "Not available");
}
return Pair.of(true, output.toString().trim());
}
public static long logStartInfo(CommandLine command, File projectRoot) {
log.info("Starting " + fullPath(projectRoot) + "> " + StringUtils.join(command.toStrings(), " "));
return System.currentTimeMillis();
}
private static void logEndTime(CommandLine command, long startTime) {
log.info("Completed " + command.getExecutable() + " in " + (System.currentTimeMillis() - startTime) + "ms");
}
private static Executor createExecutor(LineConsumer consoleLogHandler, CommandLine command, File projectRoot, ExecuteWatchdog watchDog) {
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(projectRoot);
executor.setWatchdog(watchDog);
executor.setStreamHandler(new PumpStreamHandler(new WriterOutputStream(new WriterToOutputBridge(consoleLogHandler))));
consoleLogHandler.consumeLine(fullPath(executor.getWorkingDirectory()) + "> " + String.join(" ", command.toStrings()) + System.lineSeparator());
return executor;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy