How to Exit a Process (.exec()) if the External Program hangs

java, process, process-exit, runtime.exec

Solution

Also I have read about reading the error and output streams; however, I don't think it is applicable here, or is it?

Almost certainly yes, it is applicable. Try using `ProcessBuilder` instead of `Runtime.exec` and read all the output before calling `waitFor`. For example (exception handling omitted, in particular `waitFor` may throw `InterruptedException` before the process actually exited)

    ProcessBuilder pb = new ProcessBuilder(
        "cmd", "/c", "start", "/b", "/wait", batchFile);
    pb.redirectErrorStream(true);
    Process p = pb.start();
    IOUtils.closeQuietly(p.getOutputStream());
    IOUtils.copy(p.getInputStream(), System.out);
    // or alternatively throw away the output using
    // IOUtils.copy(p.getInputStream(), NullOutputStream.NULL_OUTPUT_STREAM);
    IOUtils.closeQuietly(p.getInputStream());
    int returnVal = p.waitFor();

(IOUtils and NullOutputStream are from Apache commons-io).

To answer the actual question in the title, if your process still hangs even after properly reading its output, you may need to use `p.destroy()` to forcibly terminate the process. You could define a timer task something like

    public class TimeoutProcessKiller extends TimerTask {
      private Process p;
      public TimeoutProcessKiller(Process p) {
        this.p = p;
      }

      public void run() {
        p.destroy();
      }
    }

and then do

    // single shared timer instance
    Timer t = new Timer();

    // for each device
    Process p = pb.start();
    TimerTask killer = new TimeoutProcessKiller(p);
    t.schedule(killer, 30000);
    // ... read output stream as before ...
    int returnVal = p.waitFor();
    killer.cancel();

This will cause the process to be killed if it has been running for more than 30 seconds (adjust the `schedule` call to change the timeout).

Problem

Let me explain my software. What my software simply does is that it creates 10 threads and assigns a number of tasks to each thread. Each thread then creates a Runtime Process that will start a cmd batch file which in turn will start a program that will telnet to a device (I have about 200 of them) to poll its configuration. Here is the code for my process creation: ``` Process p1 = java.lang.Runtime.getRuntime().exec("cmd /c start /b /wait " + batchFile); int returnVal = p1.waitFor(); ``` `batchFile` is the full path of the batch file. Don't get me wrong, the software works fine up to 100% of the execution and it hanged ONLY ONE TIME at about 95%, so I'm trying to find a solution for that. Why it hanged is not my issue now, but rather how to deal with hangups later on..! Now the problem is that I need to wait for the process to finish because my telnet client will write to a file that I will read later on in the thread; and hence the use of the `.waitFor()` . My question is how can I get the thread to understand that the external program hanged? In other words, can I give the external program some time limit to finish; and if it does not the thread will kill the process? Also I have read about reading the error and output streams; however, I don't think it is applicable here, or is it?

Original source