We have 2 instances behind a load balancer running the same rails app with passenger. When we deploy, the server startup time causes requests to timeout. As a result we have a script that updates each webserver individually by taking one off the LB, deploying with cap, testing a dynamic page load, putting it back on the LB.
How can we get capistrano to do this for us with one command? I have been able to set it up to deploy to all instances simultaneously but they all restart at the same time and cause the site to be unavailable for 20 seconds.
What am I missing here? Seems like this should be a common pattern.
It's not actually that straightforward to serialize deployment in capistrano, which likes to parallelize all of its operations between servers. To restate the issue, it seems like you have a handful of servers and want to take each one offline in sequence to update the deployment.
The trick is to override the deploy:create_symlink
task in your deployment configuration:
def perform_task_offline options
sudo "take_this_server_offline", options
yield
sudo "put_this_server_online", options
end
def create_symlink_task options
# does what your existing deploy:create_symlink did, something like:
run "rm -f /web/current && ln -s #{release_path} /web/current", options
end
namespace :deploy do
task :create_symlink, {once: true, except: {no_release: true}} do
deployed_servers = Array.new
roles[:app].servers.each do |current_server|
options = {hosts: current_server}
deployed_servers.push current_server
perform_task_offline(options) { create_symlink_task options }
end
end
end
In this case perform_task_offline
includes commands that execute on the server specified in options
that remove it from the load balancer while it yield
s the block including create_symlink_task
, which creates the deployment symlink.
You should then be able to run the standard cap
command to deploy, and you'll see the servers sequentially go offline, create the "current" symlink, then come back up.
Note that the above code tracks the servers that have successfully been deployed to with deployed_servers
. If you want to be able to rollback an active failed deployment (that is, the failure happens during deployment itself) on only the servers that had previously been deployed to, you'll need a similar loop inside of an on_rollback do
block, but over only the deployed_servers
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With