0

I have a python script which downloads a text file,reads it line by line and sends the read lines to java. I need to restrict this operation to 5 seconds and receive whatever has been read by the python.

To test whether things are working correctly, I tried this:

import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

class ProcessTest {
    public static void main(String args[]) {
        try {
            File file = new File("/home/local/seconds.py");
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String testCase = "", temp = "";
            while ((temp = reader.readLine()) != null) {
                testCase = testCase.concat(temp + '\n');
            }
            reader.close();
            ProcessBuilder pb = new ProcessBuilder("python", "-c", testCase);
            Process p = pb.start();
            if (!p.waitFor(5, TimeUnit.SECONDS)) {
                reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
                while ((temp = reader.readLine()) != null) {
                    System.out.println(temp);
                }
                p.destroy();
                System.out.println("not ended");
            } else {
                System.out.println("ended");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

seconds.py file

from time import sleep
for i in range(1,11):
    print(i)
    sleep(1)

Expected result: As I have specified the process waitFor value as 5 seconds, the code should be printing only up to five.

Obtained result: The code executes for more than 5 seconds and it prints up to 10.

How can I set the timeout for a process and print the contents in the buffer?

Prasanth G
  • 103
  • 11
  • I tried without p.wait(). Still the code is printing up to 10. – Prasanth G Aug 20 '19 at 12:13
  • 1
    Additionally the `reader.readLine()` probably won't return until the connection has been terminated and in that case it will probably throw an `IOException`. This [`answer`](https://stackoverflow.com/questions/804951/is-it-possible-to-read-from-a-inputstream-with-a-timeout) might help you. – second Aug 20 '19 at 12:16
  • 1
    I forgot to mention: `waitFor(5, Timeout.Seconds)` does not guarantee a waiting time of 5 seconds, you would need to handle that while processing the `Inputsteam`. Using the `readInputStreamWithTimeout` from the [`answer`](https://stackoverflow.com/questions/804951/is-it-possible-to-read-from-a-inputstream-with-a-timeout) should do that for you. – second Aug 20 '19 at 12:23

1 Answers1

0

waitFor is not correct for this situation.

waitFor will not change how much output the process produces. Regardless of how long you wait, your loop is consuming every single line of output the process can produce.

For that matter, on most systems, processes can hang if their output isn’t consumed regularly, so waitFor may not behave as expected when used with a process that prints output.

As others have pointed out, p.wait(); is incorrect here. That method has nothing to do with the Process; it is the inherited Object.wait method, which is used for cooperation between multiple threads.

The simplest approach is to simply check the elapsed time:

Process p = pb.start();
long startTime = System.currentTimeMillis();
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((temp = reader.readLine()) != null) {
    long time = System.currentTimeMillis();
    if ((time - startTime) >= 5000) {
        p.destroy();
        System.out.println("not ended");
    }
    System.out.println(temp);
}
if (temp == null) {
    System.out.println("ended");
}
reader.close();
VGR
  • 40,506
  • 4
  • 48
  • 63
  • `readLine()` would still block, so in a case - when there is no new input available - it would stop there till the nextLine arrives (or an IOException is thrown). I didn't just want to copy the solution from the linked answer, but feel free to integrate it into your answer yourself. – second Aug 20 '19 at 14:43
  • 1
    @second You’re correct, but this seems to be a simple case, and I suspect high accuracy isn’t a goal. For precise accuracy, I’m pretty sure an interruptible Channel would be needed, along with an additional thread (which some answers in that other question do in fact recommend). But that seems out of scope here. – VGR Aug 20 '19 at 15:01
  • Sometimes, when I read some answer I feel that people, who know the answer anyway just assume certain things, but don't mention them explicitly for those that do not know. -- Anyway while `p.waitFor` might not be suitable for the 5 seconds time limit, it is suitable for having a `fallback` in case where the process does not produce output within the given time. – second Aug 20 '19 at 15:44