When people first start using the Java Service Wrapper, they are usually interested in how to integrate their application with the Java Service Wrapper to run as a Service or to have their application monitored. Once an application is setup and integrated with other systems, the question of how to shut down often comes up.

There are a number of reasons why you would want to shut down an application in different ways. When a shutdown needs to be controlled by another application or system, for example, pressing CTRL-C is not an option.

We have been asked many times about the options available for controlling the shutdown process of the Wrapper, and decided that it was a good idea to collect them all in one place.

Solution

As with many aspects of the Java Service Wrapper, it has been designed to be as flexible as possible to make integration with most Java applications possible. Over the years, we have built in several ways of controlling the Wrapper and its JVM to meet the needs of a wide variety of customers.

Please take a look over the examples below to find which method (or methods) works best for you. The first few are most likely obvious, but some may be new even to experienced Wrapper users.

Technical Background

Before getting into the different methods of shutting down the JVM, we will cover a few closely related topics that you need to understand or at least be aware of when thinking about shutting down your application.

Shutdown Hooks

Starting with Java 1.3, Java included the ability to register a special thread, called a shutdown hook, which will be executed by the JVM when it is ready to be shut down. Without a shutdown hook, an application would have no way of knowing that it was being shut down. Thus, it would have no way of knowing that it needed to complete any in progress work, and save any data that needed to be preserved.

We won't go into shutdown hooks in detail here, but here is a quick example of what one looks like and how to register it with the JVM.

Register a Shutdown Hook:

Script Example of Registering a Shutdown Hook:
Thread shutdownHook = new Thread( "myapp-shutdown-hook" )
    {
        public void run()
        {
            System.out.println( "Starting MyApp shutdown..." );
            // Do some cleanup work.
            System.out.println( "MyApp shutdown complete." );
        }
    };
Runtime.getRuntime().addShutdownHook( shutdownHook );

It is possible, and common, to have multiple shutdown hooks registered. Usually each application or major component will register its own shutdown hook if needed. Registration of shutdown hooks should be done as part of the initialization process so a shutdown will be handled correctly regardless of its timing. In most cases, you can register a shutdown hook and then forget about it.

Remove a Shutdown Hook:

It is usually possible to code the shutdown hook without doing so, but if you find that you need to remove a shutdown hook at some point, it can be done as follows:

Command Example of Removing a Shutdown Hook:
Runtime.getRuntime().removeShutdownHook( shutdownHook );

JVM Shutdown:

When the JVM starts to shut down, it will loop over all of the registered shutdown hooks and launch them each as a new Thread. These shutdown hook threads will then run in parallel until all of them have completed. When the last shutdown hook completes, the JVM will immediately exit, killing any other threads that are still running.

Shutdown Hook Log Example:
jvm 1    | Starting MyApp shutdown...
jvm 1    | ...
jvm 1    | MyApp shutdown complete.
wrapper  | <-- Wrapper Stopped

One problem with shutdown hooks is that they can potentially take hours to complete. During this time, there is normally no way to tell Java to shut down early. The Wrapper works around this problem using the configurable JVM Exit Timeout, discussed below.

Shutdown Timeout

When you start to shut down the JVM that has been integrated with the Java Service Wrapper, the JVM will execute the Wrapper's internal shutdown hook. The Wrapper uses its own shutdown hook to initiate a clean shutdown of the application wrapped by the Wrapper, and then clean up after itself.

If you are like most users, and use Integration Method #1 (WrapperSimpleApp) or Method #4 (WrapperJarApp) for your application, then the Wrapper's shutdown hook will complete almost immediately.

However, if you are making use of Integration Method #2 or Method #3, then the Wrapper's shutdown hook will run until the application has been stopped. For Method #2 WrapperStartStopApp, this is when the main method of the registered shutdown class completes. For the Method #3 WrapperListener implementation, this is when the WrapperListener.stop() method completes.

The Wrapper defines a shutdown timeout, which is the maximum amount of time that it will allow the Wrapper's shutdown hook to take to complete. If the Wrapper's shutdown fails to report that it has completed within this timeout period, then the Wrapper will assume that the shutdown process has frozen and kill the JVM forcibly. This is done to work around shutdown problems that would otherwise leave the application in an unusable state. The shutdown timeout defaults to 30 seconds and can be configured using the property wrapper.shutdown.timeout.

Shutdown Timeout Log Example:
jvm 1    | Stopping...
wrapper  | Shutdown failed: Timed out waiting for signal from JVM.
wrapper  | JVM did not exit on request, terminated
wrapper  | <-- Wrapper Stopped

JVM Exit Timeout

After the Wrapper's shutdown hook has completed and the Wrapper has been notified that the JVM is ready to shut down, the Wrapper goes into a mode where it is simply waiting for the JVM to exit on its own. Remember that the JVM launches all of the registered shutdown hooks in parallel. It will wait until the last one has completed and then exit. If any of the other shutdown hooks take a long time to complete, then this could take a while. Like with the Shutdown Timeout above, the Wrapper is designed to time out after a while to avoid getting into a state where the application is not available. This timeout defaults to 15 seconds, and can be configured using the property wrapper.jvm_exit.timeout.

JVM Exit Timeout Log Example:
jvm 1    | Stopping...
jvm 1    | Stopped.
wrapper  | Shutdown failed: Timed out waiting for the JVM to terminate.
wrapper  | JVM did not exit on request, terminated
wrapper  | <-- Wrapper Stopped

Once the last of the shutdown hooks has completed, the JVM process should terminate almost immediately. One known cause of the exit taking a long time is when a dump file is being saved when JVM heap profiling has been enabled.

Technical Overview

Now that the main issues around application shutdown are understood, let's get into the options for shutting down an application.

Pressing CTRL-C

Compatibility :1.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

The first method that you will most likely encounter is simply pressing CTRL-C while the Wrapper is running in a console or terminal. This method does not require any special development and can be used with pretty much any application.

Windows:

When the user presses CTRL-C on Windows, the Wrapper forwards the request on to the Java process. Java then handles the request by launching all shutdown hooks that have been registered within the application.

Log Example of Immediate CTRL-C Shutdown (Windows):
...
wrapper  | CTRL-C trapped.  Shutting down.
jvm 1    | Starting MyApp shutdown...
jvm 1    | ...
jvm 1    | MyApp shutdown complete.
wrapper  | <-- Wrapper Stopped

UNIX:

On UNIX platforms, CTRL-C causes an INT signal to be sent to the Wrapper. This causes the output to look slightly different.

Log Example of Immediate CTRL-C Shutdown (UNIX):
...
wrapper  | INT trapped.  Shutting down.
jvm 1    | Starting MyApp shutdown...
jvm 1    | ...
jvm 1    | MyApp shutdown complete.
wrapper  | <-- Wrapper Stopped

CTRL-C:

Sometimes when you are developing an application, it can become tiresome to always wait for the application to shut down cleanly. If you really want to shut it down immediately, the Wrapper allows you to press CTRL-C a second time to kill the JVM. While very useful, this has the drawback of data possibly not being saved correctly because the shutdown hooks did not run to completion.

Log Example of Immediate CTRL-C Shutdown:
...
wrapper  | CTRL-C trapped.  Shutting down.
jvm 1    | Starting MyApp shutdown...
wrapper  | CTRL-C trapped.  Forcing immediate shutdown.
wrapper  | JVM did not exit on request, terminated
wrapper  | <-- Wrapper Stopped

Disable CTRL-C:

Most users like this feature, but just in case you want to make sure that the JVM is always given a chance to shut down cleanly, you can disable the immediate shutdown feature using the wrapper.disable_forced_shutdown property starting with Wrapper version 3.5.15.

There are also cases in which you want to intentionally prevent your users from being able to stop the application with CTRL-C. This can be easily accomplished using the wrapper.ignore_signals property. Please note that if you do this, you will of course need to use one of the other methods to shut down the application.

Log Example of Ignored CTRL-C:
wrapper  | CTRL-C trapped, but ignored.

Sending a TERM signal (UNIX)

Compatibility :1.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :Windows (Not Supported)Mac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

On UNIX platforms, it is also possible to send a TERM signal to the Wrapper process. This is in fact how the shell script shipped with the Wrapper requests that it shuts down by default.

The TERM signal works almost exactly like the CTRL-C method above.

Log Example of TERM Signal Shutdown:
...
wrapper  | TERM trapped.  Shutting down.
jvm 1    | Starting MyApp shutdown...
jvm 1    | ...
jvm 1    | MyApp shutdown complete.
wrapper  | <-- Wrapper Stopped

You can send this signal from the command line using the following command.

Command to shut down the Wrapper with a TERM Signal:
kill {pid}

The {pid} should be replaced with the process Id of the Wrapper. If you wish to do this programmatically, you can have the Wrapper store its current process Id in a pid file using the wrapper.pidfile property. If you are using the Wrapper shell script, then this file should exist by default in the same directory as the Wrapper binary.

The wrapper.ignore_signals property can be used to disable this kind of shutdown as well.

Log Example of Ignored TERM Signal:
wrapper  | TERM trapped, but ignored.

Service Stop (Windows)

Compatibility :1.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSX (Not Supported)Linux (Not Supported)IBM AIX (Not Supported)FreeBSD (Not Supported)HP-UX (Not Supported)Solaris (Not Supported)IBM z/OS (Not Supported)IBM z/Linux (Not Supported)

When running as a Windows Service, it is possible to stop the service using any one of a number of commands:

In any case, when a command is issued to request that a service be stopped, the Windows Service Control Manager will control the service shutdown process and then report back when complete. The Wrapper will always respond by attempting to shut down the JVM cleanly.

Log Example of Stopping a Service:
jvm 1    | ...
jvm 1    | Stopping...
wrapper  | <-- Wrapper Stopped

When shutting down the entire system, the Wrapper will be shut down by the OS prior to shutdown. Some Windows versions will ignore the reports that the service is shutting down and simply kill the service if it takes too long. If this happens, you may see a truncated log file, as the Wrapper and its JVM will have been forcibly killed by the OS.

System Shutdown Log Example:
wrapper  | User logged out.  Ignored.
wrapper  | Machine is shutting down.
jvm 1    | Stopping...
wrapper  | <-- Wrapper Stopped

Anchor File

Compatibility :3.1.1
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

The Wrapper can be configured to output an anchor file using the wrapper.anchorfile property. An anchor is used by ships to keep the ship from floating away. The Wrapper uses this file in much the same way. It will create the anchor file on startup, and then periodically check to make sure it still exists. When and if the file is ever deleted, the Wrapper will immediately start the shutdown process.

Log Example of Shutting Down the Wrapper with an Anchor File:
jvm 1    | ...
wrapper  | Anchor file deleted.  Shutting down.
wrapper  | <-- Wrapper Stopped

NOTE

If this method is used, it is of course important to protect the anchor file to make sure that only users who should be able to delete the file can do so.

On UNIX, if you have modified the shell script to ignore system signals, it will use this method to control when the Wrapper should be shut down.

Command File

Compatibility :3.2.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

The Wrapper can be configured to look for a command file which can contain any one of a number of commands that the Wrapper will interpret. The location of this file can be specified using the wrapper.commandfile property. It is disabled by default.

Commands are issued by simply creating a text file containing the command. The file will be deleted by the Wrapper as soon as the command is processed.

Example of wrapper.command File:
STOP
Log Example of STOP command with Command File:
jvm 1    | ...
wrapper  | Command 'STOP'. Shutting down with exit code 0.
jvm 1    | Stopping...
wrapper  | <-- Wrapper Stopped

If this method is used, it is of course important to protect the directory where the command file will be located to make sure that only users who should be able to issue commands can do so. Please see the wrapper.commandfile property documentation for a full list of available commands, along with several more examples.

Action Server

Compatibility :3.0.4
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

The Wrapper comes with an optional class that enables you to connect with any Telnet client to remotely control the Wrapper. Making use of this method requires that you add a few lines of code to your application. Please take a look at the Javadocs for the WrapperActionServer class for a full explanation.

To set up a simple server that will only allow the client to shut down the Wrapper, please try adding the following code:

Configuration Example:
int port = 9999;
WrapperActionServer server = new WrapperActionServer( port );
server.enableShutdownAction( true );
server.start();

Additional actions can be enabled by calling the appropriate methods listed in the Javadocs.

Once this is set up, you can now connect to the application with a command telnet localhost 9999. When connected, simply press the S key, and the Wrapper will shut down cleanly. This can be a potential security risk, so be sure to protect this port if used. It is also possible to bind the listening socket to localhost, thus preventing remote connections.

Forcibly Killing the Wrapper

Compatibility :1.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

As a last result, or as part of your testing, you may wish to forcibly kill the Wrapper process. On Windows, you can do this by opening up the Task Manager, locating the wrapper.exe file on the Processes tab, then pressing End Process. On UNIX, you can accomplish the same thing by using a variant of the kill command, kill -9 {pid}. In both cases, you need to be very careful not to terminate the wrong process.

When you kill the Wrapper process in this way, it is immediately terminated and will not have a chance to shut down the JVM cleanly. The Wrapper is designed such that its Java component will start the Java shutdown process automatically. This is critical to avoid the JVM becoming an uncontrolled zombie process.

When killed, the Wrapper's log file will simply stop the logging at that moment. Any Java log output beyond this point will not make it into the log file.

Forcibly Killing the Java Process

Compatibility :1.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

The Java process can be forcibly killed in much the same way as the Wrapper process. Once again, this should not normally be done except as part of your testing. You can use the wrapper.java.pidfile property to request that the Wrapper write out the Java process' process id.

By default, when the JVM is killed in this manner, the Wrapper will assume it was a crash and restart the application in a new JVM.

Forcibly Killed JVM Log Example:
jvm 1    | ...
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | WrapperManager: Initializing...
jvm 2    | ...

If you kill the Java process like this, it will not have a chance to run any of its shutdown hooks, and will thus not be shut down cleanly.

Calling System.exit(0)

Compatibility :1.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

There are also several ways to stop the JVM from within the JVM. The most common method, which also does not require any Wrapper-specific coding, is to simply call System.exit(0). When this happens, the JVM will start its regular shutdown process, including running all registered shutdown hooks.

JVM Shutdown with System.exit(0) Log Example:
jvm 1    | ...
jvm 1    | Stopping...
wrapper  | <-- Wrapper Stopped

The argument to the exit method is used to specify an Exit Code for the JVM. Exit Codes can be very useful in helping the application that started the JVM understand what happened. The Wrapper is able to recognize different exit codes and then take various actions depending on what you wish to do. Please see the wrapper.on_exit.<n> property page for more information.

Java also provides you with Runtime.getRuntime().halt(0), which makes it possible to shut down the JVM without running any of the registered shutdown hooks. While this can be useful in some cases, we do not recommend its use with the Wrapper, as the Wrapper will not have any way of knowing that the JVM was shut down intentionally. When the JVM exits in this way, the Wrapper will interpret it as a JVM crash or unexpected exit, and thus restart the JVM.

JVM Shutdown with Runtime.getRuntime().halt(0) Log Example:
jvm 1    | ...
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | WrapperManager: Initializing...

If you really need to shut down without running shutdown hooks, please try the WrapperManager.stopimmediate(0) method below.

Calling WrapperManager.stop(0)

Compatibility :1.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

Another method is to make use of the Wrapper API by calling WrapperManager.stop(0). When this happens, the JVM will start its regular shutdown process, including running all registered shutdown hooks.

JVM Shutdown with WrapperManager.stop(0) Log Example:
jvm 1    | ...
jvm 1    | Stopping...
wrapper  | <-- Wrapper Stopped

Calling WrapperManager.stopImmediate(0)

Compatibility :3.0.4
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

If you wish to shut down the JVM without running any of the registered shutdown hooks, you can do so by calling the WrapperManager.stopImmediate(0) method. This will notify the Wrapper that the JVM is planning to shut down, but then do so without running the shutdown hooks.

JVM Shutdown with WrapperManager.stopImmediate(0) Log Example:
jvm 1    | ...
wrapper  | <-- Wrapper Stopped

Filter Trigger Actions

Compatibility :3.0.0
Editions :Professional EditionStandard EditionCommunity Edition
Platforms :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/OSIBM z/Linux

The Wrapper has a feature that lets you register filters on the JVM console log output and then perform any of a number of actions when there is a match. One such action is the SHUTDOWN action. Please see the wrapper.filter.action.<n> and wrapper.filter.trigger.<n> properties for a full list of available actions.

Filters can be very powerful because they make it possible to add functionality to an application without requiring any Java coding. A filter can be setup entirely within the Wrapper configuration file.

To shut down the JVM whenever the application logged the text Oops, you would specify a set of properties as follows.

Filter Configuration Example:
wrapper.filter.trigger.1=Oops
wrapper.filter.action.1=SHUTDOWN
Matched Filter Log Example:
jvm 1    | Hey I heard someone say Oops...
wrapper  | Filter trigger matched.  Shutting down.
jvm 1    | Stopping...
wrapper  | <-- Wrapper Stopped

NOTE

One potential security issue to keep in mind with this feature is that a user could potentially cause a filter to be matched if there is a way to log any input data directly to the console.

Misc. Actions

There are also a number of other features besides the filters that allow you to specify that a certain action takes place. These can all specify a SHUTDOWN action. Examples are the following properties:

Reference: Shutdown

The Java Service Wrapper provides a full set of configuration properties that allows you to make the Wrapper meet your exact needs. Please take a look at the documentation for the individual properties to see all of the possibilities beyond the examples shown above.