Simple database backups using a nightly CRON job and Capistrano



2010/05/06 // Leeds // // Feed



Limerick Rake by Thoughbot provides a useful set of Rake tasks to help simplify common tasks. One that I use quite a lot is the backup task which performs a mysqldump of the specified environments’ database. It looks roughly like this:

# http://github.com/thoughtbot/limerick_rake/blob/master/tasks/backup.rake
# lib/tasks/backup.rake
namespace :application do
  desc "Backs the applications database up for the given environment"
  task :backup => :environment do
    
    config           = ActiveRecord::Base.configurations[RAILS_ENV || 'development']
    database         = config['database']
    filename         = "#{database.gsub(/_/, '-')}-#{Time.now.strftime('%Y-%m-%d-%H%M%S')}.sql"
    backup_directory = File.expand_path(File.join(RAILS_ROOT, '..', '..', "shared", "backups"))
    backup_path      = File.join(backup_directory, filename)
    binary           = %x[ which mysqldump ].strip
    
    options   =  "-e -u #{config['username']}"
    options   += " -p#{config['password']}" if config['password']
    options   += " -h #{config['host']}"    if config['host']
    
    raise RuntimeError, "I only work with mysql." unless config['adapter'] == 'mysql'
    raise RuntimeError, "Cannot find mysqldump." if binary.blank?
    
    FileUtils.mkdir_p(backup_directory)
    
    puts "Backing up #{database}"
    %x[ #{binary} #{options} #{database} > #{backup_path} ]
    puts "Backed up #{database} => #{backup_path}"
    
  end
end

There’s a couple of ways I like to use this. Firstly, to ensure that the database is cloned before a deploy using Capistrano. By hooking it into a before callback I can ensure the database is backed up before any code is updated:

# config/deploy.rb
namespace :deploy do
  before "deploy:update_code", "deploy:backup"

  desc "Backs up the applications database to RAILS_ROOT/../shared/backups"
  task :backup do
    run "cd #{deploy_to}current && rake application:backup RAILS_ENV=#{rails_env}"
  end
end

This does the job for small to medium sized sites, larger ones would have much more rigourous backup procedures. Another way is to use it on a nightly CRON job, which might be more useful for preserving day-to-day snapshots of your database. In your crontab:

0 1 * * * cd /path/to/project && RAILS_ENV=production /usr/bin/env rake application:backup >> log/backup.log 2>&1

This way you cover your back between deploys and keep daily copies of the database should the worse ever happen.

Other (possibly related) posts

Comments