I'm executing a shell pipeline from a java program - it'll be something like
ProcessBuilder builder = new ProcessBuilder(
"sh", "-c", "program1 | program2 | program3");
builder.start();
In some cases this unit might need to be terminated. However
process.destroy();
Will only destroy the "sh" command. The commands in the pipline will be orphaned and adopted by the init process.
Is there any way to easily terminate all these child processes - or execute a pipeline like the above in a way that makes it easier to terminate them . Altering progam 1/2/3 can't be done. Portability beyond linux is not a issue.
There's two ways I can think to do this:
You could run a pkill program1 program2 program3
You could write a intermediate program which launches the whole bash command line, this intermediate program would install a signal handler which kills it's own children when it gets a STOP signal.
Instead of running the pipeline in the shell, build the pipeline in java.
You'll need three process builders then (one for program1, one for program2, and ... one for program3 :D), and some threads to transfer the output from each process' output stream to the input stream of the next process.
This way you get j.l.Process instances for each of the childs, and can call destroy() on those.
Create a wrapper program in C that (a) launches the rest of the pipe, and (b) handles some signals by killing all the participants in the pipe before calling exit(2) itself.
Related
I have a few doubts on process termination. My use case is such that
Java process invokes a shell script process through Process Builder
The shell script invokes a new process x
Does process.destroy() in java also kill the process x along with shell script?
What happens when the Java process is killed while x is running? Is both shell script process and process x killed?
There is no tie between a child process and its parent.
Both process can know each other ids, but there is not a hard link between them.
Generally what happens to children of a process when it is killed is platform dependent, so there is not guarantee that when you kill a process created from java also the children of that process will be killed too. Additionally you program can have different behaviour on different operating systems.
I want to run a shell script from within a Java program asynchronously-- i.e. after the java program starts execution of that shell script, it carries on with other operations-- and does some further work only when the shell script returns a response to it.. i.e. it does not explicitly stop and wait for the shell script's response.
Is this possible/feasible? How do I implement such functionality?
Basically i will be monitoring multiple servers using a single server that will manage all those servers-- for this it will run shell scripts on each of those servers...since there are many servers, and in java its recommended that number of threads not exceed number of cpu cores... hence I need a solution to this problem, that is not dependent on threading (because of threading limitations)...so that I can simultaneously (or near-simultaneously) fire off many such shell scripts without waiting for one of those scripts responses' (as waiting would affect processing for other shell script commands)... another issue.. the shell commands need to be invoked either on local machine or on remote machines and response is needed from both types of shell script execution(viz local execution and remote execution)...
did you try anything?
you can try something like:
ProcessBuilder builder = new ProcessBuilder("your command to launch script");
Process process = builder.start();
And it does NOT wait by default for the process to complete, so you can execute your code next.
And if you want to do some processing after the process is finished you can try:
int exitVal = process.waitFor();
When you execute another process and want to obtain a result from it, you usually have to read the output of that process, as the process might block if its output buffer becomes full. The easiest way to achieve this is by having a single thread in your Java application which starts the script and then reads its output into some buffer. Other threads of the Java application can do whatever they want to do, and if the process is done, the thread can signal others about that event and then terminate.
I don't know where your recommendation to not use more threads than CPUs originates from, but I'd not hold with that in general. This is true for worker threads, where each active thread keeps one core busy, but in your case, most threads would be idle most of the time. There is some OS level resource overhead associated even with idle threads, so if there are really really many processes, using a single thread to read from all the streams would be better, but a lot more complicated.
You can use Runtime.exec or ProcessBuilder in a different thread than your application main thread to run your shell script asynchronously.
This post shows how to use Runtime or ProcessBuilder. Read this post to learn java threads if you are not aware of it.
I have a shell script starting two java processes. How to ensure that when shell script process is killed, all It's children will be killed too? For example when I try to kill It, java processes remain alive:
kill -9 myscriptID
You can check for all java processes by running this:
ps -aux | grep *java*
This looks like it can help as well.
Your kill command only kills your script, not other processes that it has spawned. Best way to kill all child processes has some great answers for killing the whole tree.
That said, it seems that a better design would be to keep track of the PIDs of the child processes, and rather than sending the parent SIGKILL, send it SIGTERM (or have some other way) to trigger it to gracefully kill its children.
I am using Java Runtime to run commands, including certain CVS commands.
I use:
process = runtime.exec ("cmd /C cvs...");
format for running the Process in Java
I need to have the option of stopping it. For this I use the Java Process destroy method
process.destroy();
However only the cmd is stopped not the cvs process. It continues to run as a separate process without the cmd process as the parent. There are many references to this on the internet, but I haven't found any satisfactory solution. Thanks
This is a problem with the windows cmd shell. Why do you use it? Can't you do exec("cvs ...") instead?
It may be possible using Runtime.exec to get the PID of the process you have run. And with that you might be able to shut down the process tree.
You would however need 2 other programs to find the PID and to terminate the process tree.
I would like some help understanding and implementing a 'wait until process complete' between the various processes in my application, which need to proceed in a step-wise fashion. My java file runs a batch file which then runs a script. At the conclusion of this there are series of commands that I need to run (through the command line) in a consecutive manner. I'm using:
Runtime.getRuntime().exec("cmd /c start " + command)
to run my batch files and commands (not sure if that information is relevant). Right now what is happening is that the second step that needs to occur in my application is executing before the first step (running the batch file which runs a script) has completed. I need the first step to conclude before running the next series of commands. I really hope I'm making sense!
exec() returns an instance of Process, on which you can do waitFor().
Watch out though: I think "start" will actually spawn off a separate Windows process, so waitFor() may return before the command has finished. Try removing "start" from the command line?
Easy:
just call the method waitFor() of your Process instance.
It will stop the thread until the external process is terminated;
Could you put that series of commands into its own batch file?
Otherwise, you could use ProcessBuilder to get a Process object, and call waitFor() on it:
causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
EDIT: Actually, exec() returns a Process, so you don't need to bother with the ProcessBuilder part at all.