Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
capistrano skip NoMatchingServers
# Allows Tasks that have no servers to be skipped instead of raising a NoMatchingServersError
module Capistrano
class Configuration
module Connections
def execute_on_servers(options={})
raise ArgumentError, "expected a block" unless block_given?
if task = current_task
servers = find_servers_for_task(task, options)
if servers.empty?
#raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
logger.info "skipping `#{task.fully_qualified_name}' because no servers matched"
return
end
if task.continue_on_error?
servers.delete_if { |s| has_failed?(s) }
return if servers.empty?
end
else
servers = find_servers(options)
raise Capistrano::NoMatchingServersError, "no servers found to match #{options.inspect}" if servers.empty?
end
servers = [servers.first] if options[:once]
logger.trace "servers: #{servers.map { |s| s.host }.inspect}"
max_hosts = (options[:max_hosts] || (task && task.max_hosts) || servers.size).to_i
is_subset = max_hosts < servers.size
# establish connections to those servers in groups of max_hosts, as necessary
servers.each_slice(max_hosts) do |servers_slice|
begin
establish_connections_to(servers_slice)
rescue ConnectionError => error
raise error unless task && task.continue_on_error?
error.hosts.each do |h|
servers_slice.delete(h)
failed!(h)
end
end
begin
yield servers_slice
rescue RemoteError => error
raise error unless task && task.continue_on_error?
error.hosts.each { |h| failed!(h) }
end
# if dealing with a subset (e.g., :max_hosts is less than the
# number of servers available) teardown the subset of connections
# that were just made, so that we can make room for the next subset.
teardown_connections_to(servers_slice) if is_subset
end
end
end
end
end
@benfyvie

This comment has been minimized.

Copy link

@benfyvie benfyvie commented May 24, 2011

If you don't want to modify and maintain a custom change to capistrano core code you can also do a manual check directly in your deploy.rb so that the task won't be attempted to be executed if there are no servers that match. For example:

namespace :deploy do     
  desc "Restart Unicorn or Mongrel depending on what is used" 
  task :restart, :roles => :app do
    unicorn.deploy unless find_servers_for_task(self.top.find_task('unicorn:deploy')).empty?
    mongrel.restart unless find_servers_for_task(self.top.find_task('mongrel:restart')).empty?
  end
end #deploy namespace
@donnoman

This comment has been minimized.

Copy link
Owner Author

@donnoman donnoman commented May 25, 2011

That's quite verbose to type out each time you need it. I guess it's acceptable if only one task is giving you grief.

However I fundamentally disagree with caps default assumption that it should abort when a task has no execution targets. You have specific control of populating the roles; its not an error that the role is empty; it's an on-purpose. Therefore the best thing to do is what is described; if there are no targets don't execute the task; instead of breaking the whole task chain!

The default assumption Is like a sore loser who dumps the chess board when you get "check!"

@levent

This comment has been minimized.

Copy link

@levent levent commented Jun 8, 2011

Has this been logged as an issue and likely to be contributed as a patch to the capistrano codebase? I wasn't able to find anything in the github project.

Cheers
L

@donnoman

This comment has been minimized.

Copy link
Owner Author

@donnoman donnoman commented Jun 10, 2011

Yes I had, I think it was submitted to whatever was used prior to github, I had a branch and even added tests for it.

donnoman/capistrano@skip_empty_servers...master

Your welcome to pursue it, I tried several times to get it included, so now I just patch my own installations and move on.

@rslifka

This comment has been minimized.

Copy link

@rslifka rslifka commented Jun 14, 2011

I'll second this initiative. We deploy a shared codebase to servers running in different roles. In some environments (e.g. development sandboxes where we won't have an entire server deployment configured) cap failing when there are no servers matching is prohibitive.

Did you submit a pull request for your patch? Would love to see the option in there.

@levent

This comment has been minimized.

Copy link

@levent levent commented Jun 16, 2011

I haven't had time to write a patch but I opened a ticket on github: capistrano/capistrano#51

@metavida

This comment has been minimized.

Copy link

@metavida metavida commented Nov 4, 2011

An update for people who come from Google (like me), a patch to capistrano/capistrano#51 was accepted in August (cap 2.7.0). That means you can now do something like the following in your tasks:

namespace :unicorn
  task :deploy, :roles => :unicorn, :on_no_matching_servers => :continue do
    # Task definition goes here
  end
end
after "deploy:restart", "unicorn:deploy"
@Jenny-White

This comment has been minimized.

Copy link

@Jenny-White Jenny-White commented Mar 10, 2013

@metavida Thanks for the followup, 1 year later !

@jinixdme

This comment has been minimized.

Copy link

@jinixdme jinixdme commented Dec 13, 2013

@metavida Thank you!! Very, very helpful :)

@infinityhacks

This comment has been minimized.

Copy link

@infinityhacks infinityhacks commented Mar 5, 2015

@metavida Thanks you, that resolves my big issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment