Search code examples
ruby-on-railsdeploymentcapistrano

Capistrano 3 - task being executed twice when in multiple roles


In my deploy.rb I have some custom tasks like this:

namespace :deploy do
  desc 'setup environment'
  task :env do
    on roles(:web) do
      invoke 'symlink:env_file'
      invoke 'config:foreman'
    end
  end

  before  'assets:precompile', 'env'
end

My server definition looks like this:

server "my.app.ip", roles: %w{app web}, primary: true
server "my.resque.server.ip", roles: %w{resque web}

Essentially my 'app' server is responsible for running the main rails app, and my resque box runs the background jobs. But they both have the web role, because they both configure/run nginx + foreman through my own custom hooks.

When I run my cap deploy command I keep running into errors like this:

Skipping task `symlink:env_file'.
Capistrano tasks may only be invoked once. Since task `symlink:env_file' was previously invoked, invoke("symlink:env_file") at config/deploy.rb:133 will be skipped.
If you really meant to run this task again, first call Rake::Task["symlink:env_file"].reenable

I really just want those commands to run once per server. My expectation based on the roles definition within the task is that those tasks would get invoked once for each 'web' server in my server group. Why is it executing things multiple times?


Solution

  • Capistrano is not designed to run arbitrary tasks within an on block. The only things that you should put inside an on block are SSH-execution commands such as:

    • test
    • execute
    • capture
    • upload!
    • download!

    You should never use invoke inside an on block.

    In your case, the on block gets executed once per :web server, which means invoke is most certainly being called multiple times.

    Instead, why not use the before declaration for both tasks?

    before 'assets:precompile', 'deploy:symlink:env_file'
    before 'assets:precompile', 'deploy:config:foreman'