Customize your continuous deployment with Heroku buildpacks

One of the great things about building on PaaS/IaaS is all the devops work you
get to avoid. One of the drawbacks is there is a different class of devops work
that come with these services. That of understanding how to manage and use them
intelligently. Overall the tradeoff is generally a win but it is good to know
all the ways in which you can customize.

Heroku is actually quite customizable via their buildpacks, which are basically
the bootstrapping scripts they run when you push code up to them.

This will be the first in a set of posts I'm going to be doing describing
building software (read: startups) exclusively using hosted services for
operations. I'm not suggesting that this is for everyone, merely describing some
of the things I've been doing and how it's been working out, for good or bad.

Getting started with a buildpack

I would recommend starting your custom buildpack from an existing template. For
that Heroku has provided all of their default buildpacks for you to use as a
base on Github. If you're using Rails you'll want
the Ruby buildpack and will likely be editing the lib/language_pack/rails3.rb
or lib/language_pack/rails2.rb.

What can you do?

That's really up to you. For me I had two problems with Heroku's default build.
Both relating to the asset pipeline.

The assets are recompiled even if there have been no changes to said assets.

The asset compilation can fail and it will still deploy the site.

The first problem just means that builds may take 2-3 minutes longer than they
have to. The second problem is far worse since Heroku just lets rails fallback
to on-the-fly compilation of assets, however since we failed to compile them
one can assume this will fail in production. This will almost always result in
500's in this situation, so it is just very, very bad.

So I searched the active forks of the default buildpack and found an already written solution for #1 here.

For the second problem, I just changed the default behavior to exit with an error code if the asset compilation fails. You can see the commit here.

Finishing Up

To get your build pack working you can you simple need to tell Heroku to use it:

Obviously this is tip of the iceberg stuff, but it goes to show you how much
flexibility you really have on Heroku. There is a downside though, Heroku
doesn't handle failures here all that well, so if it fails to pull the
buildpack from Github (which happens more often than I'd like) it just gives
up, it has no retry policy on this. So you have a bit of a reliability issue.
For me it's ok as I'd rather have to re-run a deployment than have a deployment
that will almost certainly fail. However I'm also thinking of submitting a pull
request with these changes (subject to configuration variables switches).