For Fauna, we needed to migrate the website (a Sinatra app) from Heroku to our own servers in AWS
us-west-2. I wanted to get off MRI and bundle it up as a JAR as part of this process.
We already deploy the core database as a monolithic JAR, so it made sense to deploy the website as a monolithic JAR as well. This conforms to our constraint-driven development methodology.
We also wanted to avoid having to set up a J2EE webserver to host a single WAR, but rather stick to a self-contained JVM per app. It turned out to be within the realm of straightforward.
Building a JAR from a Rack app requires three things:
- Put your code into
/libso Warbler adds it to the
- Rename your
rackupso Warbler can’t find it and builds a JAR instead of a WAR. I put mine at
- Copy the startup script from your webserver into
/bin. (I wanted to use Thick, since we already use Netty, but ultimately Puma worked best.)
Now you can run
jruby -S warbler and get a dependency-free JAR with a bundled app, webserver, and copy of JRuby.
Deployment is a little strange because Warbler/JRuby do not expose the JAR contents as a true filesystem.
Basic file operations like
require will work, but
Rack::File does not because it relies on
send_file. Neither does OpenSSL certificate loading. I tried various workarounds but ended up having the deployment script (Ansible) unzip the public folder from the JAR and managed Sinatra’s
:public_folder with an environment variable.
You may think your local JAR is working fine, but move it into an empty directory and try it from there before you deploy. Your app may be picking up the local filesystem and not the JAR for various non-Ruby dependencies. The
rackup file suffered from this issue also and needed to be unpacked.
I put a stub app on Github so you can try it out. JAR away and forget about the Linux/rbenv/nginx/passenger flavor of the week. It doesn’t affect you!
JARs are nice. JRuby needs to implement a lower-level file interface for the JAR contents, though. I’d love to see JAR support robustly embedded in JRuby itself.