Scripting Heroku Backups

With any website, having a regular backup is critical. Heroku, the awesome Rails cloud service that hosts Pocket Tabs and a handful of other sites for me, provides the ability to do backups of code and data through a concept called bundles.

When you enable the free bundles support on Heroku, you only get 1 bundle. You can download it and destroy it to free up the space for the next bundle, but results in 3-4 commands just to get a backup of the site. You can pay for additional bundles, but with a little script we can get by with just one.

Here's the typical workflow:

> heroku bundles:capture my-site-2010-02-28
> heroku bundles:download my-site-2010-02-28
  #places my-site.tar.gz in the current directory
> heroku bundles:destroy my-site-2010-02-28

With some help, I created a rake task to do this work for me.

In your rails project, place a new rake file in the lib/tasks folder. I called mine backup_site.rake. The standard Rails Rakefile knows how to load up any of your custom rake files in this folder. It's a good idea to give your rake tasks a namespace to keep everything tidy. Here's mine:

namespace :pockettabs do
    
  desc 'Captures a heroku bundle and downloads it.  The downloaded files are stored in backups/'
  task :backup do  
    timestamp = `date -u '+%Y-%m-%d-%H-%M'`.chomp
    bundle_name = "pockettabs-#{timestamp}"
    puts "Capturing bundle #{bundle_name}..."
    `heroku bundles:capture --app pockettabs '#{bundle_name}'`
    # poll for completion (warning, a little hacky)
    begin
      bundles = `heroku bundles --app pockettabs`
    end while bundles.match(/complete/).nil?
    # download & destroy the bundle we just captured
    %w(download destroy).each do | action |
      `heroku bundles:#{action} --app pockettabs '#{bundle_name}'`
    end
    
    `mv pockettabs.tar.gz backups/#{bundle_name}.tar.gz`
    puts "Bundle captured and stored in backups/#{bundle_name}.tar.gz"
  end  
end

Now I can easily just run a rake task any time I want to backup the site.

> rake pockettabs:backup
# Capturing bundle pockettabs-2010-02-28-02-40...
# Bundle captured and stored in backups/pockettabs-2010-02-28-02-40.tar.gz

Next step is to put this in a cron job so that I don't have to remember to do it.

#1 Matt Buck avatar
Matt Buck
3.25.2010
4:15 PM

I've also got a heroku plugin that automates the process of backing up bundles and uploading them to S3: herocutter.heroku.com/.../17

That gives you access to the following command:

heroku backup


#2 Nick Rutherford avatar
Nick Rutherford
7.18.2010
11:55 AM

Thanks Ben & Matt

I went with a combination of the two; basically Ben's + fileutils + a sleep delay on polling.

S3 is a nice idea but I just want local downloads for the time being.

An interesting snippet if you're on the single-bundle (free) addon is the following (to delete *any* existing bundle) at the start of your rake task, else the capture will fail telling you one already exists.

sh "heroku bundles:destroy #{app_option} $(heroku bundles #{app_option})"