29

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!

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756
  • 11
    I see this question has already received a closevote for being off topic. I would like to know why! This question is not a *superuser*-type question, it is related to how to program a Java app so that it handles `SIGTERM`s. I suspect the closevoter did not actually read my question. – IAmYourFaja Feb 07 '12 at 15:47
  • Which flavor of Linux? Not all are the same. http://www.linuxquestions.org/questions/linux-newbie-8/restart-services-service-command-not-found-88809/ – Spencer Kormos Feb 07 '12 at 15:47
  • CentOS - but that should only matter if the configuration has to be done at the shell level. If its a Java implementation then it shouldn't matter. – IAmYourFaja Feb 07 '12 at 15:49
  • @SpencerKormos regardless of what happens at the operating system level, you need to have your Java code be responsive to the operating system telling you to stop. – Thorbjørn Ravn Andersen Feb 07 '12 at 15:50
  • @Thor The question is for starting and stopping, so you need to somehow associate the service name with the Java package, don't you? – Spencer Kormos Feb 07 '12 at 16:21
  • @SpencerKormos that is not what is being asked. He wants to know what to do in his Java code to be able to shut down properly when requested to. – Thorbjørn Ravn Andersen Feb 07 '12 at 23:21
  • http://stackoverflow.com/questions/191215/how-to-stop-java-process-gracefully – Zan Lynx Aug 19 '13 at 16:52

2 Answers2

37

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`.

Edward Thomson
  • 74,857
  • 14
  • 158
  • 187
  • 1
    Thanks Edward - so does that mean I can run `service {start|stop}` on any of my Java processes? I ask because this is how one starts/stops Tomcat politely, and I'd like my Java app to behave the same. – IAmYourFaja Feb 07 '12 at 16:49
  • I'm not completely familiar with the CentOS `service` mechanism. But on Debian and Ubuntu, I use the `/etc/init.d/myProgram start` and `stop` mechanisms without any problem. – Edward Thomson Feb 07 '12 at 16:54
  • Thanks again - I'm really not trying to be difficult here, I'm just having a tough time understanding the connection between how a shell-level call (either `service start` or `start ` in your case) maps to Java being kickstarted and fed the application as an argument. I think once I understand that relation I'll be all set. Thanks again for such amazing help! – IAmYourFaja Feb 07 '12 at 17:08
  • ShutdownHook does not in any way respond to external stimuli. It is just a facility to be able to run code at exit time. – Thorbjørn Ravn Andersen Feb 07 '12 at 23:22
  • @AdamTannon The Tomcat stop scripts invoke Java code which talks to the Tomcat JVM through a network and tell it to stop. You typically do not have that luxury for ordinary non-network applications. – Thorbjørn Ravn Andersen Feb 07 '12 at 23:24
  • *sigh* Why doesn't anyone but me and the OP understand the first part of his question? He's asking how to configure init.d to start his shell script, a la this StOf entry here: http://stackoverflow.com/a/6237997/8528. – Spencer Kormos Feb 08 '12 at 16:35
  • So here it is with a little Googling: http://support.suso.com/supki/CentOS_Init_startup_scripts You need to write a shell script which either calls "java" with your class/jar info, or wraps a shell script that you wrote to start your app, and can accept the start/stop/restart options. "start" launches your app as a process, "stop" kills the process, and the ShutdownHook lets you clean up when the process is terminating. – Spencer Kormos Feb 08 '12 at 16:38
  • 1
    @SpencerKormos: I updated to add an example `init.d` to start/stop. – Edward Thomson Feb 08 '12 at 17:06
  • @EdwardThomson, by "...using the `system` command...", did you mean "...using the `service` command..." ? – Muhammad Gelbana Aug 03 '12 at 03:12
  • It's rather odd that Java, which is so often used to write processes on servers, does not provide a way to respond to the standard unix signals for managing processes on servers. If you want signal-based handling, seems like the easiest workaround is to wrap the java invocation in a shell script, and then have that script communicate with the jvm app instance via a pipe or some other means. Not easy. – algal Mar 22 '16 at 17:41
4

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));
durron597
  • 31,968
  • 17
  • 99
  • 158
Joni
  • 108,737
  • 14
  • 143
  • 193