Shutdown hook from UNIX - java

I am trying to get my Java program to exit gracefully on my unix server. I have a jar file, which I start through a cron job in the morning. Then in the evening, when I want to shut it down, I have a cron job which calls a script that finds the PID and calls kill -9 <PID>. However, it doesn't seem that my shutdown hook is activated when I terminate this way. I also tried kill <PID> (no -9) and I get the same problem. How can I make sure the shutdown hook gets called? Alternatively, perhaps there is a better way to kill my process daily.
class ShutdownHook {
ShutdownHook() {}
public void attachShutDownHook() {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
System.out.println("Shut down hook activating");
}
});
System.out.println("Shut Down Hook Attached.");
}
}

You can use code like this on Unix to trap SIGINT (#2) signal:
Signal.handle(new Signal("INT"), new SignalHandler() {
public void handle(Signal sig) {
// Forced exit
System.exit(1);
}
});

kill -9 <pid> sends a KILL signal. This signal cannot be intercepted by the program.
If you call kill <pid>, the TERM signal (15) wil be sent. In that case, the JVM will catch the signal and the shutdown hooks will be executed.

This has nothing to do with the signals the JVM is trapping/receiving but everything to do with the terrible shutdown process of Gnome, which apparently needs to be cooperative not to absolutely shit the bed (and the jdk doesn't have the api for this). If you want to see a even worse consequence of this, try to run:
dbus-monitor --profile --session type='method_call',interface='org.gnome.SessionManager'
on a shell, and logout or restart: it will crash gnome-shell and hang the computer until you login on a TTY and order a restart.
Maybe kdbus will fix this on this case, maybe not. The only thing i know is that shutdownhooks on a java application that is using AWT (not command line) will NEVER run its shutdownhooks on GNOME3. Actually, the VM will always exit with non-zero code (failure) presumably from native code. At least it doesn't hang, although this makes shutdown hooks quite useless
(i've been trying to make a workaround by using dbus-monitor, but as you can see from the example i gave, it's a bit too dangerous too).

Related

Jython JSR223 Signal Handler not Called

I am using the jython 2.7 jsr223 script engine. And I like to cleanup on termination of the jython execution.
Termination: Interrupting the thread which runs the jython script engine.
Cleanup: Registering signal handlers:
signal.signal(signal.SIGTERM, cleanup)
In the jython code I see that, as an example the sleep, reacts with throwing a KeyboardInterruot exception. Code below:
public static void sleep(double secs) {
if (secs == 0) {
// Conform to undocumented, or at least very underdocumented, but quite
// reasonable behavior in CPython. See Alex Martelli's answer,
// https://stackoverflow.com/a/790246/423006
java.lang.Thread.yield();
} else {
try {
java.lang.Thread.sleep((long)(secs * 1000));
}
catch (java.lang.InterruptedException e) {
throw new PyException(Py.KeyboardInterrupt, "interrupted sleep");
}
}
}
The above code raises a new exception: PyException(Py.KeyboardInterrupt, "interrupted sleep").
Theoretically the KeyboardInterrupt exception could be catched and the signal handler could be executed. Nevertheless the KeyboardInterrupt is not consistently thrown with all commands.
The subprocess.check_call command in jython is implemented in a way that it doesn't throw a KeyboardInterrupt exception, nor fires any SIGINT or SIGTERM when the jython execution is interrupted.
So the kill behavior might change on the implementation of the currently executing python-java equivalent (jython command).
People with similar problems say that changing the jython console would help to have SIGINT triggered. : How do you intercept a keyboard interrupt (CTRL-C) in Jython?
So I set the python.console=org.python.core.PlainConsole. The Jython code says: Alternatively, you could set python.console here,
but be aware that this will also affect the console in applications that
embed a PythonInterpreter, or use Jython as a JSR-223 script engine.
So it should affect the script engine execution through jsr223. But the SIGINT script handler is not triggered even with python.console=org.python.core.PlainConsole as a property set in the JVM.
So there it seems there is no way to cleanup when jython execution when it runs a sub-process and gets interrupted.
Nevertheless I found that the signal handler in a jython execution is executed when I interrupt the jvm which runs the node.
This thread indicates that the JVM termination does not forward the SIGTERM or SIGINT signal. But executes shutdown hooks: What happens when the JVM is terminated?
Debugging the shutdown hooks didn't reveal their execution at jvm termination.
So how and why do the SIGINT and SIGTERM handlers get executed that way?
Below is the code for testing signal handlers an the KeyboardInterrupt exception with jython:
import subprocess
import sys
import signal
import time
print 'Start'
def cleanup(signum, frame):
outputFile = open('output.log','w')
print "Starting cleanup"
outputFile.write("Start cleanup")
time.sleep(5)
outputFile.write("Finished cleanup")
outputFile.close()
print "Done"
sys.exit(0)
signal.signal(signal.SIGTERM, cleanup)
signal.signal(signal.SIGINT, cleanup)
try: outputFile = open('output.log','w')
outputFile.write("Start sleeping bash subprocess:")
outputFile.close()
subprocess.check_call("sleep 10h", shell=True)
except KeyboardInterrupt as interrupt: outputFile = open('output.log','w')
outputFile.write("Keyboard INterrupt caught")
outputFile.close()
How do I execute the python/jython SIGTERM and SIGINT signal handlers when a jsr223 jython script engine thread is interrupted (execution terminated)???
Thank you so much for your help!

Java shutdown hook not running

I have a product service in Java. In our code I am creating shut down hook, but when I stop service it is not calling shut down hook consistently. Out of 5 stop calls it has called shutdown hook only once.
Runnable shutdownHandler = new Runnable() {
#Override
public void run() {
s_log.info("Shutting down thread..");
}
};
Runtime.getRuntime().addShutdownHook(
new Thread(shutdownHandler, "shutdownthread"));
Can anybody please tell me what could be the reason behind this not getting called consistently?
Check the following code:
Runnable shutdownHandler = new Runnable() {
#Override
public void run() {
System.out.println("Shutting down thread..");
}
};
Runtime.getRuntime().addShutdownHook(
new Thread(shutdownHandler, "shutdownthread"));
and if it gives you expected output, you need to check the documentation of your logging framework.
I am also finding that my framework (Jooby) and Java shutdown hooks work fine on my Mac on IntelliJ which sends a kill SIGINT (-2) however on Ubuntu Server 20.04 LTS they don't run.
As my Java app is a webapp I came up with a simple workaround:
Setup a controller to listen to some url that isn't easily guessable e.g.
/exit/fuuzfhuaBFDUWYEGLI823y82941u9y47t3u45
Have the controller simply do the following:
System.exit(0)
Do a curl or wget from a script to the URL and the shutdown hooks all fire as JVM comes down.
I suspect for some reason on Linux there is a bug and no matter what interrupt that I use besides SIGKILL they all effectively behave like SIGKILL and the JVM comes down hard/abruptly.

Java program exit with code "130"

When I close a java program in intellJ, the following log appears in the console:
"Process finished with exit code 130"
Some times, the code is "1".
I know this is the very basic, but I googled Internet and still couldn't find the explanation for the exit code.
What does the code mean? Where can I find the explanation?
To steal #Baby 's answer from the comments and formalize it, the 130 exit code is given by bash, and Mendel Cooper's Bash-Scripting Guide states that it indicates that the process was terminated by a SIGTERM. Generally this is the user pressing Ctrl-C.
This answer is applicable if you want to get the behavior of many native apps that return code 0 after a graceful shutdown.
You can register a hook that performs the graceful shutdown, for example releasing resources retained by the app. If the graceful shutdown succeeds, this hook can also override the exit code to 0. The hook will be called on SIGTERM (happens when the user is pressing Ctrl+C).
Runtime.getRuntime()
.addShutdownHook(
new Thread(
() -> {
//graceful shutdown steps
Runtime.getRuntime().halt(0); //override the exit code to 0
}));
The solution above will prevent other hooks that may exist to run after this one. It will also prevent files to be deleted that had .deleteOnExit() called.
Another approach may be implementing and registering a SecurityManager that looks like this:
static class Converting130To0SecurityManager extends SecurityManager {
#Override
public void checkExit(int status) {
if (status == 130) {
System.exit(0);
} else {
super.checkExit(status);
}
}
#Override
public void checkPermission(Permission perm) {
// Allow all activities by default
}
}
...
System.setSecurityManager(new Converting130To0SecurityManager());
Such a security manager will always transform 130 code into 0 irrespectively to the graceful shutdown.

A java process launched from another java process without & doesn't work as expected

Suppose a little Java procces whose task is to launch other Java processes. The procedure is similar to the following:
String[] command = { "/bin/sh", "-c", "some.sh" + " &"};
Process pro = Runtime.getRuntime().exec(command);
//rest
This first option works because the &, and this another one doesn't work:
String[] command = { "/bin/sh", "some.sh"};
Process pro = Runtime.getRuntime().exec(command);
//rest
Q: What is the meaning of "it doesn't work"?
A: Both options launch the process but in the second one the child process stops working after a few seconds, however, if I inspect running processes (ps aux | grep some.sh), it is there (but doing nothing). The first option works fine, it lauches process and the child does its task.
I don't understand why when I launch child process without background it appears like active in ps processes list but it isn't doing nothing.
Launching a command in Unix with & at the end implies that it will be followed by another command. I presume that if the process is halted and doing nothing, it is likely because it isn't intelligent enough to realize that another command isn't coming.
Therefore, the reason why the first doesn't close but seems to be doing nothing is precisely because of this added &. I imagine that some.sh ends. Perhaps it shouldn't, but it is.
Please look into Apache Tomcat daemon for information concerning how to create a daemon (under section Unix daemon). In your code, you should create a shutdown variable and shutdown hook so that when your daemon is halted, you can execute code:
private volatile boolean shutdown = false;
...
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
// What to run on shutdown
shutdown = true;
}
});
Once you have this, perform some action every so often in an infinite loop (using sleep of course or your CPU would be wasted):
while(!shutdowwn) {
// Perform action here every 1000 milliseconds.
Thread.sleep(1000);
}
Apache Tomcat daemon can be run on windows as a service or just as well in Linux/Unix. Hope that helps!

How to gracefully handle the SIGKILL signal in Java

How do you handle clean up when the program receives a kill signal?
For instance, there is an application I connect to that wants any third party app (my app) to send a finish command when logging out. What is the best say to send that finish command when my app has been destroyed with a kill -9?
edit 1: kill -9 cannot be captured. Thank you guys for correcting me.
edit 2: I guess this case would be when the one calls just kill which is the same as ctrl-c
It is impossible for any program, in any language, to handle a SIGKILL. This is so it is always possible to terminate a program, even if the program is buggy or malicious. But SIGKILL is not the only means for terminating a program. The other is to use a SIGTERM. Programs can handle that signal. The program should handle the signal by doing a controlled, but rapid, shutdown. When a computer shuts down, the final stage of the shutdown process sends every remaining process a SIGTERM, gives those processes a few seconds grace, then sends them a SIGKILL.
The way to handle this for anything other than kill -9 would be to register a shutdown hook. If you can use (SIGTERM) kill -15 the shutdown hook will work. (SIGINT) kill -2 DOES cause the program to gracefully exit and run the shutdown hooks.
Registers a new virtual-machine shutdown hook.
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
I tried the following test program on OSX 10.6.3 and on kill -9 it did NOT run the shutdown hook, as expected. On a kill -15 it DOES run the shutdown hook every time.
public class TestShutdownHook
{
public static void main(String[] args) throws InterruptedException
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
#Override
public void run()
{
System.out.println("Shutdown hook ran!");
}
});
while (true)
{
Thread.sleep(1000);
}
}
}
There isn't any way to really gracefully handle a kill -9 in any program.
In rare circumstances the virtual
machine may abort, that is, stop
running without shutting down cleanly.
This occurs when the virtual machine
is terminated externally, for example
with the SIGKILL signal on Unix or the
TerminateProcess call on Microsoft
Windows.
The only real option to handle a kill -9 is to have another watcher program watch for your main program to go away or use a wrapper script. You could do with this with a shell script that polled the ps command looking for your program in the list and act accordingly when it disappeared.
#!/usr/bin/env bash
java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"
I would expect that the JVM gracefully interrupts (thread.interrupt()) all the running threads created by the application, at least for signals SIGINT (kill -2) and SIGTERM (kill -15).
This way, the signal will be forwarded to them, allowing a gracefully thread cancellation and resource finalization in the standard ways.
But this is not the case (at least in my JVM implementation: Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode).
As other users commented, the usage of shutdown hooks seems mandatory.
So, how do I would handle it?
Well first, I do not care about it in all programs, only in those where I want to keep track of user cancellations and unexpected ends. For example, imagine that your java program is a process managed by other. You may want to differentiate whether it has been terminated gracefully (SIGTERM from the manager process) or a shutdown has occurred (in order to relaunch automatically the job on startup).
As a basis, I always make my long-running threads periodically aware of interrupted status and throw an InterruptedException if they interrupted. This enables execution finalization in way controlled by the developer (also producing the same outcome as standard blocking operations). Then, at the top level of the thread stack, InterruptedException is captured and appropriate clean-up performed. These threads are coded to known how to respond to an interruption request. High cohesion design.
So, in these cases, I add a shutdown hook, that does what I think the JVM should do by default: interrupt all the non-daemon threads created by my application that are still running:
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
System.out.println("Interrupting threads");
Set<Thread> runningThreads = Thread.getAllStackTraces().keySet();
for (Thread th : runningThreads) {
if (th != Thread.currentThread()
&& !th.isDaemon()
&& th.getClass().getName().startsWith("org.brutusin")) {
System.out.println("Interrupting '" + th.getClass() + "' termination");
th.interrupt();
}
}
for (Thread th : runningThreads) {
try {
if (th != Thread.currentThread()
&& !th.isDaemon()
&& th.isInterrupted()) {
System.out.println("Waiting '" + th.getName() + "' termination");
th.join();
}
} catch (InterruptedException ex) {
System.out.println("Shutdown interrupted");
}
}
System.out.println("Shutdown finished");
}
});
Complete test application at github: https://github.com/idelvall/kill-test
There are ways to handle your own signals in certain JVMs -- see this article about the HotSpot JVM for example.
By using the Sun internal sun.misc.Signal.handle(Signal, SignalHandler) method call you are also able to register a signal handler, but probably not for signals like INT or TERM as they are used by the JVM.
To be able to handle any signal you would have to jump out of the JVM and into Operating System territory.
What I generally do to (for instance) detect abnormal termination is to launch my JVM inside a Perl script, but have the script wait for the JVM using the waitpid system call.
I am then informed whenever the JVM exits, and why it exited, and can take the necessary action.
You can use Runtime.getRuntime().addShutdownHook(...), but you cannot be guaranteed that it will be called in any case.
Reference https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/
import sun.misc.Signal;
import sun.misc.SignalHandler;
public class ExampleSignalHandler {
public static void main(String... args) throws InterruptedException {
final long start = System.nanoTime();
Signal.handle(new Signal("TERM"), new SignalHandler() {
public void handle(Signal sig) {
System.out.format("\nProgram execution took %f seconds\n", (System.nanoTime() - start) / 1e9f);
System.exit(0);
}
});
int counter = 0;
while(true) {
System.out.println(counter++);
Thread.sleep(500);
}
}
}
There is one way to react to a kill -9: that is to have a separate process that monitors the process being killed and cleans up after it if necessary. This would probably involve IPC and would be quite a bit of work, and you can still override it by killing both processes at the same time. I assume it will not be worth the trouble in most cases.
Whoever kills a process with -9 should theoretically know what he/she is doing and that it may leave things in an inconsistent state.

Categories

Resources