A Short Heroku Survival Guide

28 May 2013

The downside of services that promise to make things Magically Just Work for you are that when things go wrong – as inevitably they do – they go wrong in magical, unpredictable, and hard-to-debug ways. Heroku is no exception to this rule, as Adrian Holovaty nicely illustrates in his recent lament for the end of his personal Heroku honeymoon.

As in other areas of life, the secret to a happy and long-lasting relationship with Heroku is to start with realistic expectations and a willingness to put in some hard work. Whatever the brochures promise, Heroku doesn’t allow you to forget completely about the details of deployment. But it can, I think, offer real value over managing your own servers – especially for small organisations without full-time technical staff – and with the right preparation the pain and heartache can be kept to a minimum. Below are a few tips I’ve picked up in working with Heroku that have helped me. There’s nothing earth-shattering in here, but maybe they’ll help you too.

1. heroku run bash

This simple command is, in my experience, the biggest eye-opener for people for new to Heroku and the biggest step towards convincing them that Heroku isn’t an entirely opaque black box. It fires up a new dyno (essentially, a new server instance) with a copy of your deployed application and starts a shell session.

dave@carnap:~/projects/evans-io $ heroku run bash
Running `bash` attached to terminal... up, run.9650
~ $ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.04
DISTRIB_CODENAME=lucid
DISTRIB_DESCRIPTION="Ubuntu 10.04 LTS"
~ $ curl http://icanhazip.com
50.16.130.216

You can then interact with this shell pretty much as you would on any other UNIX box. In particular:

There are a few limitations of course: you don’t have root; the Ubuntu installation you run in is pretty minimal so you might be missing your favourite debugging tool; and incoming connections are firewalled off. But generally speaking I’ve found that debugging in this way isn’t much more painful than it is on your own VPS. And it’s certainly an awful lot better than desperately deploying hundreds of tiny commits while tailing Heroku’s log output and wondering what the hell is going on (we’ve all been there)!

Incidentally, this might be one of the few situations where mastery of (or at least minimal competence with) the venerable ed editor might actually come in handy for the modern developer as neither vi or nano is available in the standard Heroku environment. You won’t want to do much serious coding with it, but if you just need to tweak a few config values then it’s not too hard to get the basics.

2. Get to know your buildpack

Most of the really nasty magic in Heroku is not in the runtime environment but in the buildpacks: the code responsible for taking a git checkout of your application code and producing a “slug” (a filesystem snapshot) with everything needed to run your application. Fortunately, the buildpack repositories are freely accessible on GitHub and are fairly short and easy to read.

You can read the full details of the Buildpack API here (there’s very little to it), but most of the action happens in the compile phase. On GitHub, find the buildpack for whichever platform you’re running on and open the bin/compile file. You’ll find a script (almost certainly bash) whose job is to take your source code and produce a self-contained application, packaged up with all its dependencies and ready to run.

It’s really worth the time to scan through this script and get a sense of what it’s up to. This is where the dirtiest hacks live (“if this version of this dependency is specified then rename this file and set this special environment variable”) and having an idea of what these are will give you a useful starting point when things start going wrong.

3. Pin your buildpack version

Having your latest deploy break mysteriously, not because of any changes you’ve made but because Heroku silently changed the buildpack out from under you, is an incredibly frustrating experience. Fortunately, it’s easy to make sure this never happens.

First, find the appropriate buildpack on GitHub and copy the read-only repository URL. For the Python buildpack, it looks like this:

https://github.com/heroku/heroku-buildpack-python.git

Next, copy the SHA of the latest commit (there’s a handy link for this on the main repository page) and add it to the end of the git URL, preceded by a hash, like this:

https://github.com/heroku/heroku-buildpack-python.git#23493302e665dc2428f388654a1d13fd4d437b7a

Finally, tell Heroku to use this specific version of this buildpack when deploying your application:

heroku config:set \
 BUILDPACK_URL='https://github.com/heroku/heroku-buildpack-python.git#23493302e665dc2428f388654a1d13fd4d437b7a'

You’ll probably want to “watch” the repository on GitHub so you get automatic notifications when it’s updated and can update the BUILDPACK_URL with the new commit SHA. It’s a little bit more effort than letting Heroku update it automatically, but not much. And now, when your latest deployment falls flat on its face, at least you know it was probably your fault.

4. Set up Heroku error alerting

Heroku errors occur at a different level from application errors and so won’t be caught by your application’s standard error handling and notification machinery. However, if your application suddenly starts being killed for hitting its memory limits you really want to know about it. It takes a minute to set up the free version of the LogEntries add-on which will send email notifications whenever one of these Heroku errors occurs. Do it now.

Any other suggestions?

Those are my four simple tips. If you’ve found them helpful, or if you’ve got suggestions of your own to add, please get in touch.

comments powered by Disqus