lib/rubber/recipes/rubber/utils.rb
# Use instead of task to define a capistrano task that runs serially instead of in parallel
# The :groups option specifies how many groups to partition the servers into so that we can
# do the task for N (= total/groups) servers at a time.  When multiple roles are supplied,
# this tries to be intelligent and slice up each role independently, but runs the slices together
# so that things don't take too long, e.g. adding an :api role to some :app servers, when restarting
# you don't want to do the api first, then the others as this would take a long time, so instead
# it does some :api and some :app, then some more of each
#
Use instead of task to define a capistrano task that runs serially instead of in parallel
The :groups option specifies how many groups to partition the servers into so that we can
do the task for N (= total/groups) servers at a time.  When multiple roles are supplied,
this tries to be intelligent and slice up each role independently, but runs the slices together
so that things don't take too long, e.g. adding an :api role to some :app servers, when restarting
you don't want to do the api first, then the others as this would take a long time, so instead
it does some :api and some :app, then some more of each
Use instead of task to define a capistrano task that runs serially instead of in parallel The : groups option specifies how many groups to partition the servers into so that we can do the task for N ( = total / groups ) servers at a time . When multiple roles are supplied this tries to be intelligent and slice up each role independently but runs the slices together so that things don ' t take too long e . g . adding an : api role to some : app servers when restarting you don ' t want to do the api first then the others as this would take a long time so instead it does some : api and some : app then some more of each
def serial_task(ns, name, options = {}, &block)
    serial_roles = Array(options[:roles].respond_to?(:call) ? options[:roles].call() : options[:roles])
    servers = {}
    if serial_roles.empty?
      all_servers = top.roles.collect do |rolename, serverdefs|
        serverdefs.collect(&:host)
      end
      servers[:_serial_all] = all_servers.flatten.uniq.sort
    else
      top.roles.each do |rolename, serverdefs|
        if serial_roles.include?(rolename)
          servers[rolename] = serverdefs.collect(&:host)
        end
      end
      added_servers = []
      serial_roles.each do |rolename|
        next if servers[rolename].nil?
        servers[rolename] -= added_servers
        added_servers.concat(servers[rolename])
        servers[rolename] = servers[rolename].uniq.sort
      end
    end
    slices = []
    servers.each do |rolename, svrs|
      slice_size = (svrs.size.to_f / (options.delete(:groups) || 2)).round
      slice_size = 1 if slice_size < 1
      slices += svrs.each_slice(slice_size).to_a
    end
    task_syms = []
    slices.each do |server_group|
      servers = server_group.map{|s| s.gsub(/\..*/, '')}.join("_")
      task_sym = "_serial_task_#{name.to_s}_#{servers}".to_sym
      task_syms << task_sym
      ns.task task_sym, options.merge(:hosts => server_group), &block
    end
    ns.task name, options do
      task_syms.each do |t|
        ns.send t
      end
    end
  end
def serial_task ( ns , name , options = { } , & block ) serial_roles = Array ( options [ :roles ] . respond_to? ( :call ) ? options [ :roles ] . call ( ) : options [ :roles ] ) servers = { } if serial_roles . empty? all_servers = top . roles . collect do | rolename , serverdefs | serverdefs . collect ( & :host ) end servers [ :_serial_all ] = all_servers . flatten . uniq . sort else top . roles . each do | rolename , serverdefs | if serial_roles . include? ( rolename ) servers [ rolename ] = serverdefs . collect ( & :host ) end end added_servers = [ ] serial_roles . each do | rolename | next if servers [ rolename ] . nil? servers [ rolename ] -= added_servers added_servers . concat ( servers [ rolename ] ) servers [ rolename ] = servers [ rolename ] . uniq . sort end end slices = [ ] servers . each do | rolename , svrs | slice_size = ( svrs . size . to_f / ( options . delete ( :groups ) || 2 ) ) . round slice_size = 1 if slice_size < 1 slices += svrs . each_slice ( slice_size ) . to_a end task_syms = [ ] slices . each do | server_group | servers = server_group . map { | s | s . gsub ( / \. .* / , '' ) } . join ( "_" ) task_sym = "_serial_task_#{name.to_s}_#{servers}" . to_sym task_syms << task_sym ns . task task_sym , options . merge ( :hosts => server_group ) , & block end ns . task name , options do task_syms . each do | t | ns . send t end end end
Use instead of task to define a capistrano task that runs serially instead of in parallel
The :groups option specifies how many groups to partition the servers into so that we can
do the task for N (= total/groups) servers at a time.
Use instead of task to define a capistrano task that runs serially instead of in parallel The : groups option specifies how many groups to partition the servers into so that we can do the task for N ( = total / groups ) servers at a time .
# first figure out server names for the passed in roles - when no roles # are passed in, use all servers # Get servers for each role # Remove duplication of servers - roles which come first in list # have precedence, so the servers show up in that group # group each role's servers into slices and combine # figure out size of each slice by dividing server count by # of groups # add servers to slices # for each slice, define a new task specific to the hosts in that slice # create the top level task that calls all the serial ones
ns
name
options
block