Creating a Capistrano Task That Performs Different Tasks Based on Role

Creating a Capistrano task that performs different tasks based on role

The standard way to do this in Capistrano:

task :whatever, :roles => [:x, :y, :z] do
x_tasks
y_tasks
z_tasks
end

task :x_tasks, :roles => :x do
#...
end

task :y_tasks, :roles => :y do
#...
end

task :z_tasks, :roles => :z do
#...
end

So yes, you do need to write separate tasks, but you can call them from a parent task and they will filter appropriately.

Can Capistrano set variables based on a role?

There is no way to have custom variable values per role.

You can instead use the multistage extension from capistrano-ext to have different stages for your two different roles.

If different stages doesn't make sense for your deployment, you could write your own bundle:install task and run different commands based on roles

run "bundle --deployment --quiet", :roles => :web
run "bundle --deployment", :roles => :app

As noted in the comment below, this approach, however, will raise errors if the role does not have a server defined. It will also run each command serially. To work around both those issues, use the parallel helper.

parallel do |session|
session.when 'in?(:web)', "bundle --deployment --quiet"
session.when 'in?(:app)', "bundle --deployment"
end

Capistrano duplicate tasks for each role

Have a look at the multistage extension. While fairly easy to set up the tasks you need yourself, the multistage extension will do it all for you.

If you'd rather do it yourself, see the calling tasks section of the handbook. The trick is that you can invoke different tasks in order from the command line.

How to run a capistrano task within a whenever task?

Jan, you may find documentation very useful https://github.com/javan/whenever. The code example below - I just copied and edited it from the doc.

schedule.rb

# run this task only on servers with the :app role in Capistrano
# see Capistrano roles section below
every :day, at: '12:20am', roles: [:web] do
rake "app_server:task"
end

lib/tasks/test_task.rb

namespace :my_app do
desc 'test'
task :test do
puts "the task runs"
end
end

I believe it's easier to create Rake task and run it via Whenever. You can choose the Role, so basically you don't need to use Capistrano task (I believe you want to use it just because of Role).

Invoking a capistrano task on another environment

First, I think it is better to use the stage parameter of the cap command to designate the remote stage servers rather than your local stage servers. This means your command assumes :vagrant as always being the local stage.

Then if vagrant stage servers have a role which the remote servers don't have, you can execute different tasks on each stage via the following:

# Assuming the following stage definitions in deploy/production.rb and deploy/vagrant.rb respectively
server 'production.example.com', roles: %w{web app}
server 'vagrant.local', roles: %w{web localhost}

# the following will execute tasks on each host
desc 'sync database'
task :sync_database do
# executed on remote server(s)
on roles(:app) do |host|
# dump database and download it
end
# Load the servers in deploy/vagrant.rb
invoke(:vagrant)

# executed on vagrant box server(s)
on roles(:localhost) do |host|
# Create database and load dump from remote
end
end

This works because roles(...) returns all servers loaded with the given role and since each stage has a unique role, you can retrieve only what servers you want by specifying their respective role.

Normally, without invoke(:vagrant), roles(:localhost) in the example above wouldn't return anything since Capistrano only loads the servers defined in the given stage by default. To get around this, you can force load servers in your vagrant stage using invoke(:vagrant). So then, roles(:app) returns the servers for the given stage and roles(:localhost) returns your vagrant servers.



Related Topics



Leave a reply



Submit