Warming Up a Java Process
Last updated December 09, 2024
Table of Contents
The first request made to a Java or JVM web application is often substantially slower than the average response time over the life of the process. This warm-up period can usually be attributed to lazy class loading and just-in-time compilation, which optimize the JVM for subsequent requests that execute identical code.
As a result, many users find it beneficial to submit a few artificial requests into the JVM process before using it to handle real traffic. Even a simple set of no-op requests to your application can warm-up the networking and messaging parts of the stack, which usually constitute a large portion of the request overhead.
This article describes one strategy for implementing such behavior on Heroku.
Prebooting an application
In order to do anything with a process before the router starts sending it requests, you must enable Heroku’s Preboot feature. This will provide some time between when the app starts up and when it begins handling real traffic.
Creating a warm-up script
With pre-boot enabled, you can create a script that will run alongside your application and send some requests before it’s brought into the pool of active dynos.
Add a bin/
directory in the root of your project, and create a bin/warmup
file. Open that file in your favorite editor and add the following code:
until $(curl -o /dev/null -s -I -f http://localhost:$PORT); do
sleep 5
done
This ensures that the script waits until the main process has started up and bound to $PORT
before sending any requests.
To send the requests, add this code next:
for ROUTE in $WARMUP_ROUTES; do
echo "[warmup] calling $ROUTE"
curl -L "http://localhost:$PORT$ROUTE" >/dev/null 2>&1
done
This sends a single request to the routes defined by the $WARMUP_ROUTES
config variable, which you can set like this:
$ heroku config:set WARMUP_ROUTES="/ /hello /db"
This will send warm-up requests to three different routes: /
, /hello
and /db
. You will need to customize this variable to suit your application’s routes. Some users prefer to add special routes specifically for warm-up. It is not required to execute application specific logic, but it can help.
After you’ve chosen the routes, you need to add this script to your Procfile
.
Enabling the warm-up script
To use the bin/warmup
script, modify your existing Procfile
command for the web
process by adding the sh bin/warmup &
prefix to it. For example, you might have:
web: sh bin/warmup & java -jar my-app.jar
This will start the warm-up script in the background, and the java
process in the foreground.
Note that if you are running Windows locally, this script won’t work when you run heroku local
because it’s specific to Linux platforms (like the one on Heroku). In this case, you’ll need to create a Procfile.windows
and add it to the command by running heroku local -f Procfile.windows
. The Windows Procfile will contain only the java
command for the web:
entry.
Once this is complete, add your changes to Git and redeploy:
$ git add bin/warmup Procfile
$ git commit -m "warmup"
$ git push heroku master
When your app restarts, it will behave as normal, but you’ll see a few [warmup]
statements in the logs, which correspond to the routes you defined earlier.
You can find a complete example of an application that is set up this way in the sample app on Github.
Customizing the warm-up script
Because the bin/warmup
script is written in Bash, it can be customized by writing a few lines of code.
For example, if you want to repeat the warm-up requests multiple times, you could add for
loop around the curl
command. For example:
for i in {1..10}; do
curl ...
done
It is reasonable to repeat each warm-up request as much as a few hundred times, though not usually necessary.
If you’d like to make a more robust warm-up script, you can use a language other than Bash. Ruby and Python are both available on the Cedar stack, and you can even write a simple JVM app for this purpose.
Further reading
Advanced users may want to configure the JVM so that just-in-time compilation is better optimized for their application and thus improves warm-up time. A great resource for this is Java Performance: The Definitive Guide by Scott Oaks.
Please see the Dev Center for more information on Heroku’s Java Support.