Perform a command serially in Capistrano

Capistrano is a great tool for doing software deployments and other system maintenance tasks (although for anything larger, I’d recommend Chef).  One small Capistrano issue I ran into this week is that there’s no way to run a command in serial across multiple machines (commands are always run in parallel). You might want to do this if you need to make sure that at least one service in a group is available at all times, or if the service restarting is going to put some load on another resource such as a database.

Here’s the solution I came up with:

desc "Do a rolling restart of <service>"
deploy.task :restart do
  hosts = self.roles[:server].to_ary # change :server to your role
  num_hosts = hosts.size
  hosts.each_with_index do |host, i|
    puts "Restarting <service> on #{host} (#{i+1} of #{num_hosts})"
    sudo "/etc/init.d/<sevice> restart", :hosts => host
    if i < num_hosts-1
      puts "Waiting 3s before next host."
      sleep(3)
    end
  end
end