I'm getting hundreds of these process_reaper threads that build up over time in my application. Anyone have any idea what these may be? They seem to be in my use of Runtime.exec() however I'm destroying my process in a finally statement but they still show up
screen shot:
http://www.dropmocks.com/mBxM5
Process proc = null;
String line;
try {
logger.info("Trying to execute command " + Arrays.asList(command).toString().replace(",", ""));
proc = Runtime.getRuntime().exec(command);
} catch (IOException e) {
logger.info("IOException while trying to execute " + command);
return false;
} finally {
if(proc != null) {
proc.destroy();
}
}
I haven't seen this one myself so I searched a little; it seems a process reaper is related to the Linux kernel process management and is a daemon thread. It maintains the process state so that resources can be freed/released/collected on process termination and so on. This resource might help you. There is a mention on reapers in the final parts.
you must call process.waitFor() after exec and before destory (asy action)
Related
I have a java server application running on jboss. I want to kill the jboss process once there is any exception in starting the application (specifically bean initialization). I want to make sure that if there is any exception in connecting to the DB(the bean), both application and jboss process should be killed. I tried System.exit(1), but it didn't help.
Solved !!
Thanks #daveb.
I tried your solution. It worked!. But calling an external script looked a little weird to me. I was able to kill JBOSS process using System.exit(1) itself.
The key point is that System.exit(1) should be called from a new thread. Something like this.
Thread thread = new Thread(){
public void run(){
try {
System.exit(1);
} catch (Exception e) {
log.error("Exception while calling System.exit(1) {}",e);
}
}
};
thread.start();
you can put your kill command in a shell script and invoke it from your java bean using ProcessBuilder...here's an example...
String shutdownScript = "/etc/jboss-as/shutdown.sh";
try {
log.info("Executing shutdown script: {0}", shutdownScript);
String[] command = {"/bin/bash", shutdownScript};
ProcessBuilder p = new ProcessBuilder(command);
Process p2 = p.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
log.info("Output of running " + command + " is: ");
while ((line = br.readLine()) != null) {
log.info(line);
}
} catch (Exception e) {
log.error("Unable to execute instance shutdown script: "+ExceptionUtils.getFullStackTrace(e));
}
A cleaner solution (if you are using JavaEE) would be to create a #Startup bean and run some database checks, if the DB connection is down you can throw a throw a StartException which will automatically undeploy the app for you eg....
throw new StartException("Could not initialise DB connection");
I have an assignment where I must create two instances of a process and the other process must terminate when one of them is terminated. I can only do this when I close the first process created, does this means that created processes have some kind of hierarchy, even though they are both children of the same process?
Thanks in advance.
ProcessBuilder pb = new ProcessBuilder(args);
Process proc_1 = pb.start();
Process proc_2 = pb.start();
System.out.println("Child is running...wait for child to terminate");
int exitValue_1 = proc_1.waitFor();
System.out.println("Child_1 finished with exit value -> " + exitValue_1);
if(exitValue_1==0) proc_2.destroy();
int exitValue_2 = proc_2.waitFor();
System.out.println("Child_1 finished with exit value -> " + exitValue_2);
if(exitValue_2==0) proc_1.destroy();
does this means that created processes have some kind of hierarchy,
No. It's just the way you wrote your code. You are blocking until the first process exits and unfortunately if the second process exits first your code has no way of knowing this.
Since Java is not providing you with a "waitForEitherProcess" method, I think you will need to do a polling loop checking the status of the process. Periodically invoke exitValue on each process then sleep for a few milliseconds. If exitValue returns an int, the process has terminated. If it throws an exception it has not. Use this to decide which process has exited and which needs to be killed.
Process#exitValue will throw a IllegalThreadStateException if the process has not yet exited, you could exploit this.
ProcessBuilder pb = new ProcessBuilder(args);
Process proc_1 = pb.start();
Process proc_2 = pb.start();
boolean running = true;
while (running) {
try {
int exitValue = proc_1.exitValue();
System.out.println("Child_1 finished with exit value -> " + exitValue);
if(exitValue==0) {
proc_2.destroy();
running = false;
break;
}
} catch (IllegalThreadStateException exp) {
}
try {
int exitValue = proc_2.exitValue();
System.out.println("Child_2 finished with exit value -> " + exitValue);
if(exitValue==0) {
proc_1.destroy();
running = false;
break;
}
} catch (IllegalThreadStateException exp) {
}
}
I am trying to run a batch file with Runtime.exec() and then output its InputStream into a JTextArea. What I have works, but only partially. What happens is the batch file runs, but if it executes a command other than something like "echo" that command immediately terminates and the next line executes. For example, let's say I try to run a simple batch file like this:
#echo off
echo hello. waiting 5 seconds.
timeout /t 5 /nobreak > NUL
echo finished. goodbye.
The batch file executes, and the JTextArea says
hello. waiting 5 seconds.
finished. goodbye.
but it doesn't wait for 5 seconds in the middle.
I can't figure out why it's doing this. Here's what I use to run the batch file and read its InputStream.
private class ScriptRunner implements Runnable {
private final GUI.InfoGUI gui; // the name of my GUI class
private final String script;
public ScriptRunner(final GUI.InfoGUI gui, final File script) {
this.gui = gui;
this.script = script.getAbsolutePath();
}
#Override
public void run() {
try {
final Process p = Runtime.getRuntime().exec(script);
StreamReader output = new StreamReader(p.getInputStream(), gui);
Thread t = new Thread(output);
t.start();
int exit = p.waitFor();
output.setComplete(true);
while (t.isAlive()) {
sleep(500);
}
System.out.println("Processed finished with exit code " + exit);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
private class StreamReader implements Runnable {
private final InputStream is;
private final GUI.InfoGUI gui;
private boolean complete = false;
public StreamReader(InputStream is, GUI.InfoGUI gui) {
this.is = is;
this.gui = gui;
}
#Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(is));
try {
while (!complete || in.ready()) {
while (in.ready()) {
gui.setTextAreaText(in.readLine() + "\n");
}
sleep(250);
}
} catch (final Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (final Exception e) {
e.printStackTrace();
}
}
public void setComplete(final boolean complete) {
this.complete = complete;
}
}
public void sleep(final long ms) {
try {
Thread.sleep(ms);
} catch (final InterruptedException ie) {
}
}
I know my code is pretty messy, and I'm sure it contains grammatical errors.
Thanks for anything you can do to help!
You're creating a Process but you're not reading from its standard error stream. The process might be writing messages to its standard error to tell you that there's a problem, but if you're not reading its standard error, you won't be able to read these messages.
You have two options here:
Since you already have a class that reads from a stream (StreamReader), wire up another one of these to the process's standard error stream (p.getErrorStream()) and run it in another Thread. You'll also need to call setComplete on the error StreamReader when the call to p.waitFor() returns, and wait for the Thread running it to die.
Replace your use of Runtime.getRuntime().exec() with a ProcessBuilder. This class is new in Java 5 and provides an alternative way to run external processes. In my opinion its most significant improvement over Runtime.getRuntime().exec() is the ability to redirect the process's standard error into its standard output, so you only have one stream to read from.
I would strongly recommend going for the second option and choosing to redirect the process's standard error into its standard output.
I took your code and replaced the line
final Process p = Runtime.getRuntime().exec(script);
with
final ProcessBuilder pb = new ProcessBuilder(script);
pb.redirectErrorStream(true);
final Process p = pb.start();
Also, I don't have your GUI code to hand, so I wrote the output of the process to System.out instead.
When I ran your code, I got the following output:
hello. waiting 5 seconds.
ERROR: Input redirection is not supported, exiting the process immediately.
finished. goodbye.
Processed finished with exit code 0
Had you seen that error message, you might have twigged that something was up with the timeout command.
Incidentally, I noticed in one of your comments that none of the commands suggested by ughzan worked. I replaced the timeout line with ping -n 5 127.0.0.1 > NUL and the script ran as expected. I couldn't reproduce a problem with this.
The problem is definitely in timeout.exe. If you add echo %errorlevel% after line with timeout, you will see that it returns 1 if running from java. And 0 if running in usual way. Probably, it requires some specific console functionality (i.e. cursor positioning) that is suppressed when running from java process.
Is there anything I can do to get this to work while running from Java
If you don't need ability to run any batch file then consider to replace timeout with ping. Otherwise... I've tried to run batch file with JNA trough Kernel32.CreateProcess and timeout runs fine. But then you need to implement reading of process output trough native calls also.
I hope someone will suggest better way.
The ready method only tells if the stream can guarantee that something can be read immediately, without blocking. You can't really trust it because always returning false is a valid implementation. Streams with buffers may return true only when they have something buffered. So I suspect your problem is here:
while (!complete || in.ready()) {
while (in.ready()) {
gui.setTextAreaText(in.readLine() + "\n");
}
sleep(250);
}
It should rather read something like this:
String line;
while (!complete || (line=in.readLine()) != null) {
gui.setTextAreaText(line + "\n");
}
It's probably because your "timeout ..." command returned with an error.
Three ways to test it:
Check if the "timeout ..." command works in the Windows command prompt.
Replace "timeout ..." in the script with "ping -n 5 127.0.0.1 > NUL" (it essentially does the same thing)
Remove everything but "timeout /t 5 /nobreak > NUL" from your script. The process should return with an error (1) if the timeout failed because it is the last command executed.
So I've got a couple of shell scripts that run on a server. They do some time intensive data gathering and then complete. They seem to work fine when I run them from the server. I'm now trying to automate these with a Spring webapp. Everything is running and I can run the scripts through ProcessBuilder, but for some reason, when the scripts are run through ProcessBuilder they only get about halfway and then just stop responding.
I'm really hoping someone will have some thoughts on why this might be. Unfortunately due to the work I can't really post much in the way of code. I can post the webapp code that runs the processes, which I'll do down below, but I can't post the scripts. If anyone has some thoughts please chime in. Thanks.
#Entity
public class Job implements Runnable {
#Id #GeneratedValue
private Long id;
//getters and setters
#Override
public void run() {
Process p = null;
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("/opt/condor/bin/datafile"));
bw.write(this.getName());
bw.close();
p = new ProcessBuilder("/opt/condor/bin/scripts/create-filter.sh").start();
jobHelper(p);
List<String> dates = datesBetween();
status = "Running Master";
for(String temp : dates) {
String[] splitDate = temp.split("-");
String tmpYear = splitDate[0];
String tmpMonth = splitDate[1];
String tmpDay = splitDate[2];
log.info("Running Master script: master.sh " + this.getCustomer() + ", " + this.getProject() + ", " + tmpYear + ", " + tmpMonth + ", " + tmpDay);
p = new ProcessBuilder("/opt/condor/bin/scripts/master.sh", this.getCustomer(), this.getProject(), tmpYear, tmpMonth, tmpDay).start();
log.info("Entering job helper");
jobHelper(p);
log.info("exited job helper");
}
status = "Finished Master";
log.info("Finished Master");
} catch (IOException ioe) {
log.error("IO Error: " , ioe);
ioe.printStackTrace();
}
log.info("Done running script");
endTime = Long.toString(System.currentTimeMillis());
status = "Ended";
JobManager.FinishJob(this);
}
private boolean jobHelper(Process p) {
log.info("inside job helper");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
try {
while ((line = br.readLine()) != null) {
log.info(line);
if(line.contains("Uh oh!"))
return true;
}
boolean running = true;
while(running) {
log.info("waiting...");
p.waitFor();
log.info("done waiting");
running = false;
}
} catch (IOException e) {
log.error("IO Error: " , e);
e.printStackTrace();
} catch (InterruptedException e) {
log.error("Interrupted Exception: ", e);
e.printStackTrace();
p.destroy();
}
return false;
}
}
I apologize for any syntactical errors you see, the code does compile and run so please just ignore them. I was copying and pasting the relevant bits of code and may have messed up something in that regard.
EDIT
I added some log statements in different places and can see that the code is entering my helper, which is why it is displaying output, but at some point it just stops. it doesn't ever seem to hit the log statements surrounding the p.waitFor() method. Clearly I'm not doing something right, which is understandable since threads are a huge weakpoint of mine. I'm guessing maybe it is getting hung up displaying stuff and I'm then getting a deadlock situation but I really don't understand where or how to fix it. Can anyone let me know what I'm screwing up and what I need to do to fix it? I could really use an example as well, thanks.
I can not help much without more context on why your process is hanging. However, your entity should not be runable. Extract this to a service, you can store your process id in you entity if you need to map it back to a process.
Well after more research it seems that the problem was related to me not properly getting all the data from the input and error streams. I guess you're supposed to have multiple threads for each stream, which I still don't understand. I added a line that called the redirectErrorStream() method on the processbuilder object and that seems to have helped. I'm still not sure it won't hang again when processing greater amounts of data as I've seen a bunch of talk about all the streams needing to be in their own threads as I mentioned, but I'm not really sure how I'm supposed to do that. It's very hard to find a good concise example of how to use ProcessBuilder. However, this seems to have fixed the problem I was having.
Im trying to get console output from an external application in my application. When i call the externall app from my code it hangs with the message:
Configuring logging...
Configuring log4j from: C:\GPAT\log4j.cfg
and nothing happens. I searched through internet and it seems that it might be thread issue. But i cant modify this external application and i must go through log4j. I read the external app like this:
StringBuffer output = new StringBuffer();
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(GSATCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
System.out.println("Test running...");
String line = null;
while ((line = input.readLine()) != null) {
System.out.println(line); // Writes the test output to console
output.append(line); output.append("\n");
}
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
System.out.println("Test successfully executed");
} catch (Throwable t) {
t.printStackTrace();
}
Thanks for reading.
You need to consume both stdout and stderr from a spawned process in separate threads, to prevent blocking behaviour (your spawned process will write to buffers, and block if those buffers aren't being emptied by your consuming process).
See the 2nd paragraph of this answer for more details and a link to a suitable fix.