// you’re reading...

All

Disable deploying to your database server in Capistrano

Update: I found a better way, see below

I use Capistrano to not only manage deployment tasks, but also to do lots of data management and monitoring tasks. By default Capistrano will try to deploy your code to whatever server you have set to the :db role, and will try to run the migrations there too. I don’t want to hassle with getting our full rails environment working on the db server so this was always a hassle.

A temporary solution was to just set the :db role to the same server as the :app role and the migrations would get run on the app server and all would be well. Later though if I had tasks that needed to actually work on the db server I’d have to manually change the :db role value. Very annoying.

To avoid this you have to do two things. First, on your :db role, add the :no_release option like so:


role :db,  "db.server.com", :primary => true, :no_release => true

This will ensure you don’t have your codes updated to the db server. Next you need to overwrite the default migrate task to not use the :db role. To do this just get the task code from your deploy.rb file. On my system this was in:

/Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/recipes/deploy.rb

(I admit this is annoying because when you upgrade capistrano you may have to repeat this but I wasn’t able to figure another way.) Grab the migrate task and simply change the role it uses. It should end up looking like this:

 task :migrate, :roles => :app, :only => { :primary => true } do
    rake = fetch(:rake, "rake")
    rails_env = fetch(:rails_env, "production")
    migrate_env = fetch(:migrate_env, "")
    migrate_target = fetch(:migrate_target, :latest)

    directory = case migrate_target.to_sym
      when :current then current_path
      when :latest  then current_release
      else raise ArgumentError, "unknown migration target #{migrate_target.inspect}"
      end

    run "cd #{directory}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate"
  end

Note that the role was changed to :app (from :db). And you’re done!

But wait! There is a better way!

Jamis Buck over in #capistrano eventually replied to a question I had there and explained that there is a much simpler solution:

[10:34am] jamisbuck: flippyhead: just set one of your app servers to :db, :primary => true
[10:35am] filmprog: so you've go and added new tasks to deploy:migrate ?
[10:35am] jamisbuck: and then put your db server in the :db role, with :no_release => false
[10:35am] jamisbuck: and without :primary => true
[10:35am] jamisbuck: then you'll have your db role
[10:35am] jamisbuck: but your migrations will run on the app server in question
[10:35am] flippyhead: I can refer to role :db twice?
[10:36am] jamisbuck: flippyhead: totally. there's no reason not to
[10:36am] flippyhead: ah, no kiddin!
[10:36am] jamisbuck: the migrations only run on :db where :primary => true
[10:36am] jamisbuck: any other :db server is ignored
[10:36am] jamisbuck: (by the migration task)

See, as it turns out you can “overload” roles. So instead of all that I just use this now:

role :db,  "server.com", :primary => true
role :db,  "db.server.com", :no_release => true

And everything works!

Just remember on those db only tasks to include :only => {:primary => false} to refer to the actual db role not the app db role.

Discussion

No comments for “Disable deploying to your database server in Capistrano”

Post a comment

You must be logged in to post a comment.

Recent Comments

Most Emailed