I've inherited a Java web-services code-base (BEA/Oracle Weblogic) and need to start/launch an external background application from a web-service.
I've already tried:
ProcessBuilder pb = new ProcessBuilder(arg);
pb.start();
as well as:
Runtime.exec(cmdString);
But am experiencing strange behaviors when launching applications in this manner (i.e. the launched application stops working even though the process is still active. -- The application works fine when manually run from a normal command line).
Is there a better way to launch an external processes?
EDIT: ----------------------
I have some additional information that may help shed some light on the problem.
The process we are trying to start will require hours to complete so waiting for completion (using waitfor()) in the webservice will not be an ideal scenario.
Yes, the process we are trying to start from the webservice was created by a fellow team member [cue: your eyes roll... now]
I have had success when I use process builder to start a bash script, where the external application is launched as a background process (using "&").
#!/bin/bash
java -jar myApp.jar &
This obviously creates an orphaned process but at least the application does continue to execute.
Simply put: if the launched application writes to SDTOUT/STDIN and you don't flush them frequently (see Process.getErrorStream/Process.getInputStream) then the process will block when the buffer is full (that is really small, 4KB or less).
I recommend you to invoke ProcessBuilder.redirectErrorStream() before starting the process. Then, after that, create a thread with the run() method along the lines of:
public void run() {
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
By "stops working even though the process is still active" I am assuming you might be expecting some output from the application you have launched and not getting anything.
Try using the following:
ProcessBuilder pb = new ProcessBuilder(arg);
Process p = pb.start();
p.waitFor();
waitFor() causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
http://java.sun.com/javase/6/docs/api/java/lang/Process.html#waitFor()
Firstly, is this happening on Windows or on Linux? Also, what is the launched application supposed to more or less do? (is it a script? is it a binary? is it your binary?)
EDIT
OK, so starting a bash script (using ProcessBuilder) which in turns spawns a new JVM (java -jar myApp.jar) works.
What happens exactly when you try to spawn the new JVM directly using ProcessBuilder? You originally said:
the launched application stops working
By launched application do you mean "java -jar myApp.jar", when invoked directly, not via an intermediate bash script?
What are the exact and complete parameters (and their values) you pass to the various ProcessBuilder methods (and in which order) when you try to launch Java directly and this new JVM stops working? (e.g. provide annotated code)
If you install lsof on your *nix machine, what file is shown to be associated with file descriptor 2 (look at the FD column) when running: lsof -p 1234 (where 1234 is the process ID of the "hung" JVM?) It might be interesting to attach the entire output of the lsof command here.
What is appended to the file you have identified in step 3 above (for file descriptor 2), up to several seconds after you issue the command: kill -QUIT 1234 (where 1234 is the process ID of the "hung" JVM?)
Are you properly handling the standard input and output of the process? If the standard input or output is being processed by your application and you are not properly handling it, then the process you execute will hang waiting for I/O.
A way to test this is to write a script that runs your program, redirecting standard input, output and error to files. Then have your web service app run the script instead of the program. If the program runs to completion this way, then the problem is handling of the output of the process.
I'm guessing that the problem might be the thread that launches the process gets TERMINATED or whatever after the request is over. Try having a single thread in the applicaton that you are sure is kept alive always, you can use this for starting the processes by making calls to it from other threads.
Related
I have a Java program which starts another process with ProcessBuilder like the following:
String commands[] = {"ruby", "/home/scripts/script.rb"};
ProcessBuilder builder = new ProcessBuilder(commands);
Map<String,String> map = builder.environment();
map.put("TYPE", "sometype");
try {
builder.start();
} catch (IOException e) {
e.printStackTrace();
}
Some time after the process starts executing (a small Ruby Script which should not terminate) the Java program exits.
The problem is, once the Java program finishes executing, all sub-processes are closed, also the Ruby Script.
I found some similar questions but the answer was always, the Process is independent. But it is not like that in my case, the Ruby code will always stop executing if the Java program exits.
I tried the Java code on a Debian Jessie System with Java 8u66
The problem is, once the Java program finishes executing, all sub-processes are closed, also the Ruby Script.
On *nix systems (POSIX really, including Debian Linux) the process is sent a HUP signal (SIGHUP or hangup) when its' parent process ends. You can use the nohup(1) command when you start a subprocess to ignore the hangup from the child process.
Alternatively, you could potentially make use of the Ruby Signal Module and use Signal.trap(HUP) to handle it some other way.
Try to use Process.getOutputStream, wait for output from the process with runs Ruby, and if it takes too much time, then you can run in the background also.
Im creating a javafx application to run a unix binary application, which limits the percent of cpu a process can use, herein i already have a cputhrottle unix binary which receives PID and CPU percentage as argument, my application just acts as a GUI for this unix binary.
When I run this cputhrottle from terminal it keeps on running, until i press - CTRL+C (this is the normal behavior).
But the problem is, when I run this unix binary with my java code, it seems, as if the program is almost immediately terminated (whereas it should be running, until I press the stop button), and because its not running & being terminated, My program cannot control the percentage of CPU a process gets.
Here's my code : http://pastebin.com/rbG3ctfH
so, is there a way to tell java to keep running the cputhrottle binary file, instead of closing it.
I've tried replacing the 56th line, and instead wrote code to execute a script, which would create a file, with some text content, & when executed he program, it did created a file, so its working, but when i add e1.printStackTrace in the catch block, it stops working for some reason.
And also, if I add sleep in the shell script, then its not executed Properly, more over no Exception is being Generated.
The command you are trying to run ("echo dkkdk|sudo....) is a shell command. You need to tell runtime.exec() to run 'bash -c echo dkkdk|sudo..'
Also be aware that runtime.exec is asynchronous and could/might/likely will return to your program before the child process completes.
Also, I could not pipe the superuser password to sudo like you are trying to do. Not saying it doesn't work for you just that I couldn't get my system to take it.
In a Java program I am running another Java program using the following command:
Process p = Runtime.getRuntime().exec("echo.bat | java -Xms64M -Xmx1G -cp "+execFilePath+" "+inputFileName+" "+inputParam);
The invocation is working fine, but if due to bad coding the executed Java file (inputFileName) is hanging, say, due to some infinite loop, a new process which got started, is not ending. Now, I need to kill that process in my code.
I am able to detect if the Java program is hanging by using TimeOut. But, I don't know how to get the process id of this executed Java program and kill it once TimeOut happens.
Any help is appreciated!
Generally, you can call destroy on your Process instance. See here
I notice however that you are starting one process and pipe its output to another. The simple approach will most probabely only kill the former (your echo.bat process).
Therefore, you need a more complex scenario. Do the following:
Start a process calling echo.bat only
Wait until it is finished
Read all of its output through its output stream (Process.getOutputStream())
Start another process, calling the java program only.
Write the read data to its input (write to Process.getInputStream())
This second process instance will be your java process
As fge mentioned above, take a look at ProcessBuilder, as it simplyfies some of the steps. Especially setting up the input stream can be accomplished before actually starting the program
I'm using Java's ProcessBuilder class to run an external process. The process should not terminate before the Java program does; it must stay alive in command/response mode.
I know that the process streams may easily 'jam' if neglected, so I've done the following:
The program reads the process's combined output and error streams in a "reader" thread, and uses a "writer" thread to manage the commands. The reader thread does blocking character reads from process output, buffers them up into Strings and dispatches the results. The writer thread writes complete "command" lines via a PrintWriter; it uses a queue to ensure that no two command writes are "too close together" (currently 100ms), and that no new command gets written before the output of the previous command is complete. I also call flush() and checkError() after every println().
This scheme works fine for a few seconds or minutes, then the reader thread hangs on the blocking read(). No errors, no exceptions thrown, no more process output. Thereafter nothing will revive the external process (short of restarting it). (BTW this happens on both Linux and Windows.)
I've looked at the code and test-cases in Jakarta Commons Exec and in Plexus Utils http://plexus.codehaus.org/plexus-utils/ but (a) neither gives an example of using a long-lived Process and (b) neither appears to be doing anything basically different from what I've described.
Does anyone have a clue what's happening here please?
Thanks!
Do you also have a thread managing stderr? You only mention the two streams.
i had implemented error, input and output stream in three sepereate threads and i can read and write to external processes without any problem.
I tested both on windows/linux with multitude of built in apps cmd/bash as well as other cmd line binaries and it works fine except on some occasions it just throws io stream exception, what i do is catch the exception and restart thread again, so that program keeps on working.
If you are trying to e.g ssh in linux, then you might run across problem like you won't be able to write to same stdin, this is because of security reasons.
Try taking input from System.in and see if it works, it worked in my case
Just a guess, but have you tried un-combining the error and output streams?
I'm running Hudson as a windows service through Tomcat, with no slaves involved. The last build step in the job is a batch file that invokes some Java code. The code uses PostgreSQL's command line tool psql (via Runtime.exec()) to create a database on the local machine and eventually run some tests against it.
The job will progress to this point, then hang indefinitely without starting to create the database. If I run the batch file from the command line, it works perfectly. I don't think http://hudson.gotdns.com/wiki/display/HUDSON/Spawning+processes+from+build applies, since the process spawned doesn't even seem to begin executing, but I'm new to this so please let me know if I'm wrong.
Edit #anjanb:
The batch file's only purpose is to invoke the Java code, and the only user input is being passed in as command line arguments, which I can see are going in directly via the build's console output.
Process Explorer is showing that psql is being started, but it's obviously not being executed, since the first command psql is given is to create a new database, but that's not happening.
Edit 2: I've gotten some tips from the Hudson users mailing list, I'll try them out on Monday and report back.
Edit 3: The Java code was already consuming the output streams, I used that article when developing the code. I can't figure out what's going on, so I'm redeveloping the code to use JDBC to create the database, instead of relying on psql and Runtime.exec()
Do you read the output of the process ? If it produces more output than the OS buffers can handle, you need to read it...
Also, some processes wait until input has completed. Try to call process.getInputStream().close() after starting the process.
Maybe this article is also interesting. It's called "When Runtime.exec() won't":
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=2
There is a possibility that the program is waiting on some user input. If the service is not configured to accept user input, it will appear to be hanging.
YOu can try by configuring the service to allow USER INPUT(GUI) -- that might help.
Also, you could run Sysinternals ProcessExplorer and ProcessMonitor -- they will be able to find out where the .BAT job has stopped.