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.
Related
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 "$#"
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.
I'm running a daemon java process on my ubuntu machine :
java -cp (...) &> err.log&
The process runs for a random period of time and then just disappears. Nothing in LOGs, err.log, no JVM crash file created (hs_err_*.log), nothing. My two questions are :
1) Under which circumstances can a java process abruptly finish ?
2) IS there any way to know what happened to the process (knowing PID) ? Does UNIX keep information about finished processes somehow ?
1) Under which circumstances can a java process abruptly finish ?
When it exits by its own but I guess you ruled out that or when it is killed with SIGKILL. This might be the oom killer if you are on Linux. Did you look at the system message logs ?
2) IS there any way to know what happened to the process (knowing PID) ?
Generally not unless you configure some tracing tools to get that information
Does UNIX keep information about finished processes somehow ?
No, but depending on the Unix variant you are using, that might be something simple to add.
In your example, you can just print the process exit status with echo $?
If it is 265, that would mean the process was killed with signal 9 (=265-256).
I would write a simple shell script that somehow alerts me when the JVM terminated. Perhaps send an email with the JVM's exit code.
#!/bin/sh
# Launch JVM and wait...
java -cp ...
# do something with the exit code $?
# log it to a file or mail it yourself
Perhaps, the exit code might reveal something.
I would run it as a daemon with YAJSW as it allows several ways to monitor the memory etc, has restart options, and you can also enable log on the wrapper process so you can have much info when there is an issue.
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.
I found a weird scenario where if I start a java program and I want to exit gracefully with CTRL+C it doesn't work/respond, I have to do a CTRL+Z on the program and this is not cool, doing a ps lists the process... Anyone please.
Under Unix, command line programs have a lot of control over what happens when you try to interrupt them with ^C. The default effect of typing ^C at a terminal is to make the kernel send the SIGINT signal to the foreground process group, and the default behavior of SIGINT is to kill the process it's sent to, but both of those things can be changed.
The most likely cause of your problem is that your Java program is intercepting SIGINT in order to do some cleanup before exiting, but the signal handler is buggy so the process doesn't ever actually exit. The second most likely cause is that the program is ignoring SIGINT altogether. And the least likely cause is that it's put the terminal into "raw mode" so that ^C just delivers a byte with value 0x03 to its standard input (if it had done that ^Z probably wouldn't work either).
If you have access to the source code of your program, you can try to fix the buggy signal handler and/or make it stop ignoring the signal. Otherwise, you're kinda up a creek. You can try ^\ (control-backslash), which sends a different normally-lethal signal (SIGQUIT), but this is not guaranteed to work either, and if it does work, it may leave you with a gigantic "core dump" file to get rid of.
The only 100% for sure way to get rid of a malfunctioning process is to send it signal 9 (SIGKILL). Unlike the other lethal signals, it's impossible to intercept, block, or ignore that one. There is no control key to send signal 9; you have to suspend the process with ^Z, or open a new terminal window / ssh session, find the process ID with ps, and use the kill command. Always try kill PID before kill -9 PID.
I had the same problem (In my case it was problem :)), my issue was that I launched the app using javaw instead of java.
javaw is running the app without console so the CTRL+C is not working.
Another question about the difference between javaw to java here - What is the difference between 'java', 'javaw', and 'javaws'?