Roll your own Heroku slugs
heroku.com is a great tool for simplifying deployments of your webapps. You just add the heroku git repository to your app and push your source and it’ll build your app for you.
On my current project we’ve been using this mechanism up until recently, but we have since changed our set up. Instead of pushing our source to the heroku git repository, we build the heroku slug ourselves then ‘release’ the slug to the target server.
What’s a slug?
A slug is an archive of resources that make up your web app. Here’s the heroku definition.
As our application grew in size, the build time grew also (we are compiling a Play! scala app – so some compilation work needs to be done). The build time on the target servers was starting to hit the 15 minute mark which is when the built-in slug compiler throws a time out error.
By building the slug on our own dedicated server, we could optimise that server for the build at hand and give it more firepower so it can do its crunching. The build that was taking ~15 minutes now takes ~3.5 minutes.
Build Once, deploy many times
Every time we wanted to deploy to one of our pipeline servers (dev, qa, staging) each one would have to do its own build. Now, we build the slug once on our server and release it to each heroku target. This saves alot of time as each release takes ~1.5 minutes.
You need to do 3 things to set this up:
1. Build the slug yourself
2. Host the slug at a url on the interweb
3. Tell the heroku server to download the slug at the url provided
Everything you need to set this up is available on github.
Build the slug yourself
For building the slug we use the slug-compiler gem.
Host the slug at a url on the interweb
Once the slug is compiled we boot up a web server to temporarily host the slug at a randomized url.
Tell the heroku server to download the slug at the url provided
To notify heroku you make a REST call. You can use heroku-anvil to do this for you. In our case we created our own script to make the call so it would fit in with our url generator. The REST call in heroku-anvil is here. Note: if you’re making the rest call you’ll need your api key.
Once the release has been downloaded, we then kill the web server so the slug is no longer available. Obviously this is optional and depends on how you want to set up your script.
Thats it – if you’re suffering from slow heroku builds this provides you with an avenue to optimise your build process.
It’s worth mentioning that heroku has a new beta feature called ‘pipelines’ which allows you to send your slug upstream from one heroku server to another. We’re not using this yet, but looks like it’ll be a great addition. This means we’ll only need to build once and release once, then use the pipeline feature from there. More info here: https://blog.heroku.com/archives/2013/7/10/heroku-pipelines-beta