views:

1201

answers:

5

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.

A: 

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.

Vasil
+1  A: 

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.

Eddie
+2  A: 

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

  1. By launched application do you mean "java -jar myApp.jar", when invoked directly, not via an intermediate bash script?
  2. 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)
  3. 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.
  4. 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?)

Cheers, V.

vladr
Thanks for your additional questions. I edited my question to include the following: "Yes, the process we are trying to start from the webservice was created by a fellow team member [cue: your eyes roll... now]"
Nate
Also, the same behavior is being demonstrated on both Windows and Linux.
Nate
+2  A: 

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

Martin
Thanks for your suggestion Martin. Unfortunately, I cannot use a "waitFor()" as the process I am trying to start can take up to 4 hours to complete. -- I have since edited my main question.
Nate
+2  A: 

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);
    }
}
Antonio