Graceful kill of Apache Commons Exec process - java

I am starting an external process in my Java program (on Linux) and I need the ability to send it a SIGTERM signal rather than the SIGKILL that exec.getWatchdog().destroyProcess() is sending. Is there a way that I can more gracefully stop a unix process started with commons-exec? Or can I get the PID so that I can just run the appropriate kill command myself?

ExecuteWatchdog class has method for killing process.
So, you could just create a watchdog with long timeout and use it to kill process when neccessary, i.e.
executor.getWatchdog().destroyProcess();

Well, Commons Exec relies on the Java Process class, which doesn't expose a PID. It's also what is used to kill the process, so it's not something you can change the behavior of. All nice and encapsulated. Gotta love OO, eh?
If you are simply launching processes in to the background, you can wrap them in a simple shell script that captures the PID for you, and then saves that off to a "known place" that your Java routine knows about. Still kind of messy, and, naturally, it doesn't port to other platforms well.
You can write your own exec function using JNI to capture this information for you as well, but that's likely less friendly.
You could write a platform specific exec launcher daemon in something more system oriented (C, Python, etc.). You send IT messages to launch and stop things, and it handles that process for you. One benefit of this is that you don't have to fork the JVM when you run a new process (which can be quite expensive depending on your JVM size).
You can start the daemon up at the beginning and share a socket or a pipe (both pretty portable). That's actually not a horribly INelegant solution, and it compartmentalizes a lot of system specific behavior (so you can have a completely different process on, say, Windows vs Unix and your Java stays the same, you just need to port your little daemon), without having to run JNI.

Well you could grep it, for ex :
for i in $(ps -ef | grep -i "[Y]ourClassName" | awk '{print $2}'); do kill -9 $i; done
This is in case that you have it running more than 1 time(although it works if you have just one project), notice the [] in grep, that is so the grep doesn't give you its own process pid and -i stands for ignore case, awk is for printing second column only that is PID number.

Related

Creating a Nohup Process in Java

Using ProcessBuilder, I've been trying to create an independent process that doesn't get terminated when the JVM gets terminated, but nothing seems to work.
I've tried /usr/bin/nohup commands, but that still seems to terminate when the JVM that launched it is terminated. Is there any way to accomplish this in Java?
Well, first things first lets write a test script that validates what you're seeing:
$ cat /tmp/test.sh
#!/bin/bash
for sig in SIGINT SIGTERM SIGHUP; do
trap "echo Caught $sig" $sig
done
echo Traps registered, sleeping
sleep 10
echo Done sleeping, exiting
When I invoke this via:
new ProcessBuilder("/tmp/test.sh").inheritIO().start().waitFor(1, TimeUnit.SECONDS);
I see the Java process terminate after 1 second (since waitFor() timed out), but the subprocess keeps going (the Done sleeping message is printed to the console after the JVM exits). This lines up with what's discussed in this question.
So the first thing I'd suggest doing is validating your initial assumption that the subprocess is in fact being killed; perhaps something else is going wrong that causes it to die for another reason. Using .inheritIO() can help debugging, in case the subprocess is generating error messages you're not seeing.
All that said, nohup may not be what you want, as 'that other guy' notes; nohup only causes a process to ignore SIGHUP, and it will still respect other signals, notably SIGINT and SIGTERM (Process.destroy() sends a SIGTERM, for instance). See this question for more.
As with all problems in programming, introducing more layers would probably help :)
Create a shell script that handles the desired disowning logic, e.g.
$ cat start-and-disconnect.sh
#!/bin/bash
# obviously tweak this as necessary to get the behavior you want,
# such as redirecting output or using disown instead of nohup
nohup "$#" &
The advantage here is that Bash (or whatever shell you prefer) has better process-management control than Java, and now you can test it in isolation, without needing to compile and run your Java application.
Once you're happy with the script, your Java code simply becomes:
new ProcessBuilder("/path/to/start-and-disconnect.sh", "/path/to/your_binary.sh")
.inheritIO().start().waitFor();
You can safely .waitFor() the call to complete, since start-and-disconnect.sh will exit after starting its subprocess.

Gwt process id which run using runtime.getExec("<tcl file>") function

I need to execute a tcl file which gives output util we stop the process from java. So I use
Process proc = Runtime.getRuntime().exec("< tcl file >");
I need to get the process id (PID) to stop the process.I can run that same tcl file multiple times, so I can't get pid using getting name of executing file. Give me some methods to get process id using JAVA when running a external program.
output of ps command :
25014 pts/0 00:00:00 tclfile
29998 pts/0 00:00:09 tclfile
30866 pts/0 00:00:00 tclfile
Each instance is different I need to stop only specified process at a time, can't terminate all by killall -9 tclfile command .
The pid is not exposed to Java, since Java is platform-agnostic and pids are platform-specific. So you aren't going to be able to get the actual pid without using native code, sorry.
But if you just want a handle to the child process which you can later kill, you can do that in pure Java. The Process object has methods destroy() (which kills the process) and waitFor() (which waits for it to exit). In Java 8 it also has isAlive() and destroyForcibly() methods.
OK, after poking around on the net to find source code for ProcessImpl in various JREs, it looks like on Windows ProcessImpl has a field handle which presumably is the Win32 handle returned by CreateProcess, and on Linux UNIXProcess has a field pid which appears to be the process ID. If you wanted to be really hacky (and unsupported, and potentially tied to a specific JDK implementation, etc. -- all the usual caveats apply), you could potentially access those fields by reflection if you need to.
That said, a better solution would be to write the native code yourself, or else delegate to a helper process (e.g. in bash like Donal Fellows' answer).
You can't get the process ID from the Process object; it knows it (strictly, it's known by an object inside of a class that isn't part of the public API) but won't tell you. The simplest method of getting the PID turns out to be to get the subprocess to tell you that value by writing it to its standard out (or standard error, but that's less common) as its first action. You then can just read a line, parse the integer out of it, and there you go.
Getting Tcl scripts to print their PID is trivial. Just put this line in:
puts [pid]
# Or: puts stdout [pid]
If you can't change the Tcl script, you can use a shell script trick to wrap it in something that writes the value:
#!/bin/sh
echo $$
# exec, in bash, *replaces* the process implementation with another program
exec tclsh "$#"

How to terminate JVM run from shell script?

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.

killing a bash process does not kill the process the bash is currently running

The scenario is as follows: I have a java daemon, which is supposed to not terminate. However, in case of an unexpected error, the crashed JVM should be restarted by a script. So I wrote a command which starts a background bash which has a loop starting the JVM (so when the JVM terminates, it will be restarted again).
/bin/bash -c "while true; do java ...; done" &
In order to be able to stop the daemon, I thought of killing this bash background process (by saving it's process id in a file). This works insofar as the background bash doesn't restart the JVM, but still doesn't kill the currently running process - so the bash seems to end it's current command before it checks for a kill command. I would like to have the currently running JVM to be killed, too.
Since I don't want to manage 2 PIDs (one for the background bash and one for the currently running JVM), is there a way of "force kill" which by design stops the current command? (I couldn't find such thing in man kill)?
There are a number of process-management tools built for exactly this purpose: runit, daemontools, upstart... even an entry in the SysV inittab table.
All of these will automate restarting immediately on shutdown, track desired status as opposed to current status (and attempt to signal startup or shutdown as-desired), manage signal delivery, etc.
You can trap signals in bash and trigger events on them, but that only handles the subset which can be trapped (you can't trap a KILL, for instance). The better thing is to use a tool built-to-purpose.
The ProcessManagement page of the wooledge.org wiki (used by irc.freenode.org's #bash channel) has some other concrete suggestions on doing this yourself in bash... though it too suggests runit, daemontools, and their kin as the best-practices approach.
Why not use cron to start your app, and manage only 1 pid, the one belonging to your app? That way you'll always be killing the correct process.
Emphasising a bit, you could create a bash script to manage your app: start|stop|status. On start it will save the java pid to a file. Then you can schedule a cron job to verify the status of the app, and if the pid does not exist, relaunch it.
Isn't this the default behaviour of bash? I thought for example zsh does the opposite and doesn't send a SIGHUP to all child process? Maybe you can try this answer and write a little script and start it with disown?
see this question: Tie the life of a process to the shell that started it
I didn't test it but I need zsh in my webserver because I start it manually and exit my shell with double CTRL-D.

How To Start Jetty Properly

this really silly question probably, as no one else seems to be having this problem. In the Jetty documentation it says jar -jar start.jar starts Jetty, and it does. But when I close my SSH console, obviously it dies.
How do I run it PROPERLY?
Is this for running on a production machine that will actually serve up an application running under Jetty? I assume this is the case, since you're asking about starting it properly.
If so, you need a proper process supervision system, such as runit, daemontools, monit, upstart, systemd, or good ol' SysV init.d (as mentioned w/ a gist). Which to use depends on your preferences, business needs, and often, your underlying operating system.
I use and prefer runit. It is built on solid principles (daemontools), and for my preferred distribution (Debian and Ubuntu) it is nicely packaged by the author himself.
Despite being recommended in other answers, and mentioned in comments, starting a long running process in screen/tmux, or via nohup is sub-optimal. You don't have any real control over the process. It won't be restarted if it dies. You have to manually find its PID and otherwise manually manage the service. You have to do more manual work to get the log output (redirection, sending to some random file, etc). You cannot reliably make it depend on other processes, or have other processes depend on it. Decent process supervision systems provide all this functionality for you by default.
If your goal is something else entirely, then please update the question to be more specific about your use case.
java -jar start.jar &
(to run in the background) should also work, though logging won't be transmuted as nice as w/nohup.
This is because killing the shell that started a process (e.g. by logging out) will kill process to unless they're background processes. Screen works since as well since it runs in the background, and screen effectively keeps your session running while you attach/detach.
One way is to use nohup
nohup java -jar start.jar
This has the advantage of writing stdout and stderr to a file
Another way would be to use screen
If you're on a *nix system, the best solution is may be using a script in /etc/init.d (or whatever your system's equivalent is). There's one at https://gist.github.com/404672.
Otherwise, using nohup or screen from the command-line will at least have the process not die when you log out. So will putting the process in the background with &.

Categories

Resources