Running your Clojure app as a daemon is very useful especially when you’re ready to take it live for several reasons.
- You need a way to easily and consistently “background” or disassociate from the controlling tty for every deployment.
- Systems often start daemons at boot time (think about when your server is rebooted intentionally and more often…unintentionally).
- Something a monitor script can execute if your application becomes unresponsive or unruly.
There may be others, but those are the main reasons.
Those unfamiliar with the Java ecosystem may feel especially lost in this area, but fear not because here is an awesome solution. I am going to walk you through getting your application running as a daemon using a great piece of software made by Tanuki. I do not work for Tanuki, nor do I even know anyone at Tanuki, and so trust me this isn’t some lame plug for a product. I’ve used it for many of my Java applications and now I use it with my Clojure applications. It is quite simply a great piece of software. They call it a “Java Service Wrapper”, but that is a bit of a misnomer. It is really a JVM Service Wrapper.
In order to start using it, you’ll need to bundle your application as a Jar file. As you’ll read from the documentation on the Tanuki site there are several ways to “integrate” with the service wrapper. However, I find that using their fourth approach is the best. It is not coupled in any way to your application and there is no code to be written. Generating a Jar file is of course a breeze if you’re using Leiningen or Cake. I’m most familiar with Leiningen so you’ll want to build an “uberjar” or an equivalent Jar file that contains all of its dependencies. Wait, you’re already quandering…”will it work if I have a web app?” Yes! You can make it a War file, if you are using an embedded Jetty server. In fact, you can make your web application a Jar file if you’re using the Ring Jetty adapter and skip the complexity of a War file. Of course this is beyond the scope of the post. Before you jump off into the deep end with the service wrapper be sure that your application starts properly. Remember you’ll need a “main” function registered in the manifest of your Jar file. On the command line start it up like this:
java -jar your-nifty-clojure-app.jar
Perfect. Now you’ll need to download the service wrapper from here. You’ll see that they have thought of just about every OS distribution. If your development and production OS are the same, simply choose the right download. Or if you develop on a Mac and deploy to a Linux server like me, then choose the “Delta Pack”. The “Delta Pack” is cross platform support for those of us who develop and deploy to a multitude of OS’s. I forgot to mention I use the community edition and that is what I will be using for this setup.
I prefer to create a folder in my project called “daemon” and unzip the service wrapper contents there. Once unzipped you’ll see a directory structure like this. Begin trimming the unnecessary files by deleting the README’s, doc, and jdoc folders.
Now go into the src/bin directory and find a file called “sh.script.in”. Copy it into the bin folder of daemon directory, rename it, and lastly make it executable.
cp sh.script.in ../../bin/your-nifty-clojure-app
chmod +x your-nifty-clojure-app
Open the executable and edit the following three variables to match your application name.
APP_LONG_NAME="Your Nifty Clojure App"
Naturally you can change the PIDDIR to write where ever you want or conditionally change it based on the target environment. For starters though just put the PID file where you start the script.
Now go into the src/conf directory and find a file called “wrapper.conf.in”. Copy it into the conf folder of daemon directory, and rename it “wrapper.conf”.
cp src/conf/wrapper.conf.in conf/wrapper.conf
You’ll to make several edits to the wrapper.conf file.
Begin by telling the wrapper script that it should use the fourth integration method. Specifically it will use the WrapperJarApp as the main method and then subsequently execute your main method.
I like to set a reusable variable that sets the path to your application Jar file.
# Reusable path to the main JAR file for your application
Now you’ll need to add your Jar file to the classpath as defined in the wrapper.conf.
# Java Classpath (include wrapper.jar) Add class path elements as
# needed starting from 1
You should adjust the JVM minimum and maximum heap sizes.
# Initial Java Heap Size (in MB)
wrapper.java.initmemory=256 # Set it to whatever you see fit...
# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=512 # Set it to whatever you see fit...
Lastly, tell the wrapper script what Jar file to execute. These work like command line arguments. If your application requires arguments, feel free to enumerate them
Now you should be able to start,stop, and restart your application using the bin/your-nifty-clojure-app
Tanuki offers a bunch of other options that I haven’t even scratched the surface on and they are worth a look. I hope this helps you daemonize your Clojure application!