Process builder hangs while running Linux command occasionally - java

We are executing script and Linux command using process builder. Below is a rough example of the way we are using process builder.
class Example {
class Stopper extends TimerTask {
Thread t ;
Stopper( Thread t ){
this.t = t;
}
public void run (){
t.interrupt();
}
}
String command= <some command or script>;
String workingDirectory = <working directory>;
ProcessBuilder processbuilder = new ProcessBuilder(command);
processbuilder.setWorkingDirectory(workingDirectory);
processBuilder.redirectErrorStream(true);
Timer timer = new Timer(true);
Stopper stop = new Stopper(Thread.currentThread());
timer.schedule(stop , 5); // 5 millisec
Process process = processBuilder.start();
// code to call the thread to read the output stream.
process.waitFor();
}
In spite of reading from the output stream, the process.waitFor() get interrupted by timer thread. When thread get interrupted below is snippet of error we see ( pasting only the relevant part )
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at java.lang.UNIXProcess.waitFor(UNIXProcess.java:395)
The thread is interrupted intermittently and not always which means out by 1000 times same command run, it will timeout 10 times only. We tried increasing the timeout period but still it's not able to complete the command execution.
After searching for the issue, I see a bug in java which I feel is the issue but not sure. Any help on this is appreciated.
https://bugs.openjdk.java.net/browse/JDK-8169565

Related

How do I stop a Top Terminal Code after executing it once?

I want to see the CPU and RAM utilisation of a machine , until my java code is running. So I used top command, but I don't know how and when to stop it??
I don't know, how waitFor() can work for me?
I might run my code in a thread, but how do I tell it to wait for this thread to finish execution and stop?
MyCode
import...*;
public class MyCode {
ThreadSubclass thread1 = new ThreadSubclass();
thread1.start();
/*
I want Mycode to Run in parallel while top command stores output of RAM and CPU usage.
Can I write my code here??
When myCode is complete, stop Top command.
*/
System.out.println("0");
Process cmdProc = Runtime.getRuntime().exec("top");
System.out.println("1");
BufferedReader stdoutReader = new BufferedReader(
new InputStreamReader(cmdProc.getInputStream()));
String line;
while ((line = stdoutReader.readLine()) != null) {
// process procs standard output here
System.out.println(line);
}
System.out.println("2");
BufferedReader stderrReader = new BufferedReader(
new InputStreamReader(cmdProc.getErrorStream()));
while ((line = stderrReader.readLine()) != null) {
// process procs standard error here
System.out.println(line);
}
cmdProc = Runtime.getRuntime().exec("Ctrl+C");
}
in another fileā€¦ ThreadSubclass.java
public class ThreadSubclass extends Thread {
#Override
public void run() {
//Should I write all my code here? I had used fork earlier and it gave me pid, so It was easier for me to run my code inside that if condition of fork pid.
System.out.println("ThreadSubclass is running");
}
}
Current Output:
0
ThreadSubclass is running
1
2
TERM environment variable not set.
Expected OutPut:
0
ThreadSubclass is running
1
2
Top command output
Issues:
If I started "top" command first it didn't goes down to execute other commands.
As shown in this code, when I started Thread first, it shows "TERM environment variable not set."
if possible store it in a text file directly, rather than reading and storing it inside java code.
Process cmdProc = Runtime.getRuntime().exec("top -b > Top.csv");
error =>
top: unknown option '>'
Usage:
top -hv | -bcHiOSs -d secs -n max -u|U user -p pid(s) -o field -w [cols]

Process.waitFor hangs even though stdout and stderr get read

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()?
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.

Java subprocess terminated by itself

My application uses some daemon subprocesses for subtasks. The subprocesses are launched using ProcessBuilder and working fine on their own, but then starting them as subprocesses every associated Process.isAlive() method return FALSE. As following, no access to process is possible.
Further investigation shows the subprocesses are not started at all (don't exist in Task Manager) with no error generated at all.
Daemons typically start a separate process and exit almost immediately, which makes checks like isAlive() useless.
Often the program will have a command line switch that make the program stay in the foreground, not becoming a daemon - use that if possible. Otherwise you'll need some other way of monitoring the daemon execution, for example using the daemon's PID file.
Is the command really running? Often there are weird little issues when trying to run a program from inside Java.
For example, the PATH environment variable may not be set correctly so it fails to load a dependency.
Use this method to see if there is any console output and what the exit code is. This uses the old Runtime class instead of ProcessBuilder. It can probably be adapted to use ProcessBuilder.
public static void runExe(String[] command) throws IOException {
Runtime runtime = Runtime.getRuntime();
long start = System.currentTimeMillis();
Process proc = runtime.exec(command);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
try {
while (true) {
// enter a loop where we read what the program has to say and wait for it to finish
// read all the program has to say
while (br.ready()) {
String line = br.readLine();
System.out.println("CMD: " + line);
}
try {
int exitCode = proc.exitValue();
System.out.println("exit code: " + exitCode);
// if we get here then the process finished executing
break;
} catch (IllegalThreadStateException ex) {
// ignore
}
// wait 200ms and try again
Thread.sleep(200);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("Command took: " + (end - start) + "ms");
}

Start, stop and listen to a process in Java

I want to start a process with Runtime.exec(). Then I want to know (listen) when the process exits. Also, I want to manually stop the process if some condition met.
The code I have now is:
public class ProcessManager extends Thread{
private static ProcessManager manager;
Process process;
private ProcessManager(){
}
public static ProcessManager getInstance(){
if(manager==null){
manager=new ProcessManager();
}
return manager;
}
public void run(){
Runtime runtime = Runtime.getRuntime();
process = runtime.exec("c:\\windows\\system32\\notepad.exe");
//cleanup();
}
public void cleanup(){
//I want to do stuffs until the program really ends;
}
//called to manually stop the process
public void stopProcess(){
if(process!=null){
//TODO: stop the process;
}
}
}
As shown in the code, my program is like notepad.exe, which pop up a window and immediately returns. How can I listen to the status of the program, and wait until it is closed, as well as close it explicitly?
How can I listen to the status of the program, and wait until it is
closed, as well as close it explicitly?
You can use Process#waitFor()
// cause this process to stop until process p is terminated
p.waitFor();
As JavaDoc says
The java.lang.Process.waitFor() method causes the current thread to
wait, if necessary, until the process represented by this Process
object has terminated. This method returns immediately if the
subprocess has already terminated. If the subprocess has not yet
terminated, the calling thread will be blocked until the subprocess
exits.
I would not recommend using Runtime.exec() directly. It is not as straightforward as it might seem. Nice article "When Runtime.exec() won't" describes these pitfalls in details. For example simple code with waitFor():
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
will produce no output and hangs, because in general you need to provide handling of input, output and error streams in separate threads.
Instead you may use Apache Commons Exec library that will handle it for you:
String line = "notepad.exe";
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);
System.out.println("Process exitValue: " + exitValue);
Below is more complex example of asynchronous process terminated manually:
String line = "notepad.exe";
CommandLine cmdLine = CommandLine.parse(line);
ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout);
Executor exec = new DefaultExecutor();
DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
exec.execute(cmdLine, handler);
// wait for script to run
Thread.sleep(2000);
// terminate it manually if needed
if (someCondition) {
watchdog.destroyProcess();
}
// wait until the result of the process execution is propagated
handler.waitFor(WAITFOR_TIMEOUT);
System.out.println("Process exitValue: " + handler.getExitValue());

Why ProcessBuilder takes more time to perform a task?

I run analysis on a file directly from an analyzer program and it finishes under one minute. But if I make jar of analyzer and run it via ProcessBuilder, it does not get finished even in 8 minutes (500 sec). Here is the code I am using for ProcessBuilder. Can someone please explain the reason?
I cannot run the analyzer program directly because depending upon the input file, it may actually take 15-20 minutes which I don't want. I want to finish it under 8 minutes.
Here is code for ProcessBuilder.
public void myFun(){
String fileName = file.getName();
System.out.println(file.getAbsolutePath());
Process p;
ProcessBuilder pb;
String filePath = file.getAbsolutePath();
pb = new ProcessBuilder("C:\\Program Files\\Java\\jdk1.7.0_13\\bin\\java.exe", "-jar", "ta.jar", filePath);
pb.directory(new File("D:\\Softwares\\analyzerRun\\bin"));
long startTime = System.currentTimeMillis();
try {
p = pb.start();
long currTime = System.currentTimeMillis();
long diff = currTime - startTime;
boolean isBreak = false;
while(diff < 500000)
{
currTime = System.currentTimeMillis();
diff = currTime - startTime;
if(processIsTerminated(p))
{
isBreak = true;
break;
}
}
if(!isBreak)
{
System.out.println("Interrupting current thread!!");
p.destroy();
Thread.currentThread().interrupt();
}
else
{
System.out.println("process terminated peacefully");
}
System.out.println("Done with "+ fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static boolean processIsTerminated (Process process) {
try {
process.exitValue();
} catch (IllegalThreadStateException itse) {
return false;
}
return true;
}
Edit1:
So after given suggestions, I removed while loop and my try code looks like below now:
try {
p = pb.start();
p.waitFor();
}
Interestingly, I run this program and it does not get finished under 5 minutes. But if I run my analyzer directly, it gets finished under 30 seconds. Does ProcessBuilder not get enough priority from CPU?
Your polling loop is insane.
Suggestion:
1) start() your process
2) Save the start time.
3) Call waitFor() to block until the process is done.
4) Then take the delta.
You'll get MUCH better results - honest!
If you absolutely must run asynchronously (if your app cannot block while your subprocess runs), then create a new Java thread for steps 1) ... 4).
IMHO...
ALSO:
Run Windows Performance Monitor (or equivalent for your OS) and monitor I/O wait, CPU utilization, etc while the process is running to try to figure out where the latency might be coming from.
But your polling loop is itself introducing excessive CPU utilization. Don't do it!
Because you're wasting most of the time smoking the CPU with sleep-free polling, instead of:
(a) consuming the process's output and error streams, and then
(b) calling waitFor().
To answer this, "Interestingly, I run this program and it does not get finished under 5 minutes. But if I run my analyzer directly, it gets finished under 30 seconds. Does ProcessBuilder not get enough priority from CPU? "
After a long-time, I finally figured out that I was writing two lines on standard output in my original program. So, when I ran the jar file using ProcessBuilder, I didn't read from standard output. The process was getting hanged ultimately getting killed by the main-class thread. I just removed those two lines from the original program and now it takes equal time in both ways.

Categories