0

I already searched the web, and the question process.waitFor() never returns indicates that it is often a problem with processes that their stdout or stderr do not get read.

We use ProcessBuilder with redirectOutput and redirectError to achieve this, and I think we should be on the safe side, see the following method we use to execute processes:

public static void execute(String directory, long timeout, File out, File err, String... command) throws InterruptedException, IOException {
    LOGGER.log(Level.INFO, String.format("executing command %s (%s)", Arrays.toString(command), timeout > 0 ? String.format("timeout = %,d[ms]", timeout) : "no timeout"));
    ProcessBuilder builder = new ProcessBuilder();
    builder.directory(new File(directory));
    builder.command(command);
    builder.redirectOutput(out);
    if(out == err) {
        builder.redirectErrorStream(true);          
    } else {
        builder.redirectError(err);
    }
    long time = System.currentTimeMillis();
    Process process = builder.start();
    try {
        LOGGER.log(Level.FINE, "waiting for process");
        boolean exited = process.waitFor(timeout, TimeUnit.MILLISECONDS);
        if(!exited) {
            LOGGER.log(Level.WARNING, "timeout reached, trying to destroy ...");
            exited = destroy(silent, process); // Helper method to destroy processes
        }
        long duration = System.currentTimeMillis() - time;
        int exitValue = process.exitValue();
        LOGGER.log(Level.INFO, "execution finished in " + duration + "[ms] => " + exitValue);
    } catch (InterruptedException | Error | RuntimeException e) {
        LOGGER.log(Level.SEVERE, "execution failed", e);
        throw e;
    }
}

Yet, the problem is that it hangs on the process.waitFor(timeout, TimeUnit.MILLISECONDS) call, even though the process should easily have finished within the timeout.

The logging output is

Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute
INFO: executing command [java, -Xmx8G, -XX:+UseG1GC, -XX:+CrashOnOutOfMemoryError, -jar, MetricCalc.jar] (timeout = 14,400,000[ms])
Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute
FINE: waiting for process

(recognize that no execution finished line is written yet)

The err file reads

... Things we write to std.err ...
Finished Metrics

and the main method of MetricCalc looks like

public static void main(String[] args) {
    .... do some stuff ...
    System.err.println("Finished Metrics");
}

which indicates that the reading works fine, the last line of the Java program has been executed and the process should have terminated.

Anyone having an idea why the process does not terminate / it still hangs on Process.waitFor()?

Markus Weninger
  • 11,931
  • 7
  • 64
  • 137
  • 1
    *" .... and the process should have terminated."* - assuming that the child process is working as you expect it to. Check to see if the child process has actually terminated; e.g. using "ps -efl" or similar. – Stephen C Oct 07 '17 at 01:58
  • @StephenC: I can still find it using `ps -efl | grep "java -Xmx8G"`, which indicates that it has not terminated. Yet, I have no idea why this is the case since the very last line of code of MetricCalc (the java program that gets run as process) has been executed... – Markus Weninger Oct 07 '17 at 02:05
  • 1
    Oh, it just came to my mind: Probably MetricCalc has some non-deamon threads running, which prevent the application from terminating... I'll have to test this... – Markus Weninger Oct 07 '17 at 02:07

1 Answers1

0

It was not a problem with Process.waitFor() but a problem with process termination.

The java application that got started used an ExecutorService that did not got shotdown correctly and left zombie threads alive which prevented process termination.

Adding executorService.shutdown() solved the problem, and the application now terminates as expected.

Markus Weninger
  • 11,931
  • 7
  • 64
  • 137