I have a Java webserver from which I'm launching an external application using Apache commons exec. On a high level, the flow is that the user will specify parameters and start the application with a POST, and will then have a status page from which they can cancel the application at any time (it could be running for days).
I'm launching the application asynchronously like this:
Map<String, String> procEnv = EnvironmentUtils.getProcEnvironment();
CommandLine cmdLine = CommandLine.parse(command);
DefaultExecutor executor = new DefaultExecutor();
executor.execute(cmdLine, procEnv, new DefaultExecuteResultHandler());
I know that while I'm handling the first POST request, I can kill the process like this:
executor.getWatchdog().destroyProcess();
But I need to respond to the POST right away so that the user can move on to the status page, which means I won't have access to that DefaultExecutor
instance from subsequent requests. How can I let the user send a separate request to cancel execution later, given that I have to assume there might be more than one user and therefore more than one instance of the application running? (I can include extra data in the response and cancel request, if necessary.)
If you have some way to identify the different running instances of the external application that can be returned to the client and used in a "stop" request, you can store a static Map<String, ExecuteWatchdog>
of the identifiers and watchdogs for all instances of the application, which can then be accessed from later requests. Something like:
private static Map<String, ExecuteWatchdog> watchdogs;
//...
public static String startApplication() {
//...
watchdogs.put(id, executor.getWatchdog());
}
public static void stopApplication(String id) {
watchdogs.get(id).destroyProcess();
watchdogs.remove(id);
}
Beware that if the user doesn't cancel execution and the application ends on its own, the entry will stay in the map, so it needs to be cleaned up periodically by removing any entries where !theWatchdog.isWatching()
.