Home » Linux » What should a Java program listen for, to be a good Linux service?

What should a Java program listen for, to be a good Linux service?

Posted by: admin November 30, 2017 Leave a comment

Questions:

In Linux you can give the following commands:

service <someService> start
service <someService> stop

As opposed to killing the process with kill -9 <someService>. As I learned in an earlier question, this is the difference between sending the process a SIGTERM (former) and a SIGKILL (latter).

So how does one go about “registering” (and coding) an ordinary JAR or WAR as a service/daemon that can be started and stopped with those commands? I would imagine that Java must have some API for handling SIGTERMs?

Thanks in advance!

Answers:

If you just want to run some shutdown specific code, the “proper Java” way to handle this would not use signals, but would instead add a generic “shutdown hook” that would run when your application was about to terminate. This is one of those least-common-denominator problems that Java sometimes suffers from. (Since not all platforms support SIGINT, in Java, no platform supports SIGINT.)

Unfortunately, you don’t get much context in a ShutdownHook, but it may still be useful:

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    public void run()
    {
        // cleanup
    }
}));

If you really need to distinguish between the signal received, or you want to support signals that Java normally ignores (like USR1), or you want to abort shutdown based on a signal, then a ShutdownHook will be mostly useless for you, unfortunately.

There is a non-supported, poorly-documented way to capture signals in the Sun JVM, using the sun.misc.SignalHandler class. This is questionably portable, though it appears that the IBM JVM also supports this.

For example – you could hook up a signal handler to listen to SIGHUP reload your server configuration, which was set up in the init.d script as the reload verb:

Signal.handle(new Signal("HUP"), new SignalHandler() {
    public void handle(Signal signal)
    {
        reloadConfiguration();
    }
});

As for configuring a Java application to be controlled using the system command, you should write a shell script in init.d program that starts it up. This simply needs to respond to the start and stop verbs and take the appopriate action. For example, this could be your /etc/init.d/my-java-program:

#!/bin/sh

case "$1" in
start)
    java /path/to/my/java/program.jar &
    echo $! > /var/run/my-java-program.pid
    ;;

stop)
    if [ ! -f /var/run/my-java-program.pid ]; then
        echo "my-java-program: not running"
        exit 1
    fi

    kill -TERM `cat /var/run/my-java-program.pid`
    ;;

reload)
    if [ ! -f /var/run/my-java-program.pid ]; then
        echo "my-java-program: not running"
        exit 1
    fi

    kill -HUP `cat /var/run/my-java-program.pid`
    ;;

*)
    echo "Usage: /etc/init.d/my-java-program {start|stop|reload}"
    exit 1
    ;;

esac

exit 0

You can now start your application by running /etc/init.d/my-java-program start, or on CentOS, you can also use service my-java-program start`.

Questions:
Answers:

You cannot define signal handlers for different signals in pure Java, like you would in a native Unix program. This means that you can’t follow common conventions of e.g. having the program reload its configuration on SIGHUP and do a clean shutdown on SIGINT or SIGTERM.

What you can do is define a shutdown hook. They are run when the virtual machine is going to shut down, e.g. after receiving SIGTERM. Here’s an example:

Runnable myShutdownHook = new Runnable() {
    void run() {
        System.out.println("I'm melting! What a world...");
    }
};

Runtime.getRuntime().addShutdownHook(new Thread(myShutdownHook));