class HerokuBench::CLI

This class is based upon Vulcan, and copies heavily.

Public Instance Methods

ab(*args) click to toggle source
# File lib/herokubench/cli.rb, line 57
def ab(*args)
    num_requests_index = args.index("-n") #hack to extract number of requests from the ab arguments.
    concurrency_level_index = args.index("-c") #hack to extract number of requests from the ab arguments.
    unless concurrency_level_index.nil? or num_requests_index.nil? then
      num_requests = args[num_requests_index + 1].to_i
      concurrency_level = args[concurrency_level_index + 1].to_i

      num_dynos = (concurrency_level/100.0).ceil
      num_dynos = 1 if num_dynos ==0

      say "Inferred #{num_dynos} instances" if options[:verbose]
      args[args.index("-n") + 1] = (num_requests / num_dynos).to_i
      args[args.index("-c") + 1] = (concurrency_level / num_dynos).to_i
    end
    num_dynos ||= 1
    multi(num_dynos, *args)
end
create(name="") click to toggle source
# File lib/herokubench/cli.rb, line 32
def create(name="")
  Dir.mktmpdir do |dir|
    Dir.chdir(dir) do

      args = ["#{name}", "-s","cedar", "--buildpack","https://github.com/wcdolphin/heroku-buildpack-apache.git"]
      args.delete("")
      result = capture { Heroku::Command.run("create", args) }
      name = /\s(.+)\.\.\./.match(result).captures[0]
      puts "Created your personal benchserver: #{name}"
    end
  end
  write_config :app => name, :host => "#{name}.herokuapp.com"
  update
end
multi(dynos, *args) click to toggle source
# File lib/herokubench/cli.rb, line 86
def multi(dynos, *args)
  error "no app yet, create first" unless config[:app]
  error "Number of dynos must be an integer greater than 1" unless dynos.to_i >= 1

  begin
    say "Using #{config[:app]}" if options[:verbose] 
    say "Benching with #{dynos} dynos and arguments #{args}" if options[:verbose]

    bencher_path = File.expand_path("../bencher.rb",__FILE__)
    num_dynos = dynos.to_i

    running_procs = {}
    ab_command = "ab #{args.join(' ')}"

    p_bar = ProgressBar.create(:title=>'Benching',:total=>1 + num_dynos*100)
    summary_result  = ApacheBenchSummaryResult.new

    num_dynos.times do  |n|
      t_file = Tempfile.new("hbench_out_#{n}") 
      pid = spawn( "ruby #{bencher_path} \"#{ab_command} \" --app #{config[:app]}", :out=>t_file.path, :err=>null_dev)

      running_procs[pid] = t_file
      summary_result.add_result(ApacheBenchResult.new(t_file))
      puts t_file.path if options[:verbose]
    end


    until running_procs.empty?
      begin
        complete_results = Timeout.timeout(0.5) do
          pid = Process.wait
          running_procs.delete(pid)
        end
      rescue Timeout::Error
        diff = summary_result.get_progress() - p_bar.progress
        p_bar.progress+= diff
      end
    end

    p_bar.finish
    summary_result.print()

  rescue Interrupt
    say "Exiting...Please be patient"
    kill_running_procs(running_procs)
    kill_running_dynos()
    say "Done"
  rescue => exception
    say("HerokuBench ran into an unexpected exception. Please contact @wcdolphin",:red)

    begin
      kill_running_procs(running_procs)
      kill_running_dynos()
    rescue
    end #squelch exceptions when killing procs

    say(exception,:red)
    puts exception.backtrace
  end
end
update() click to toggle source
# File lib/herokubench/cli.rb, line 150
def update
  error "No app yet, create first" unless config[:app]

  Dir.mktmpdir do |dir|
    Dir.chdir(dir) do
      system "git init -q"
      system "git remote add origin git@github.com:wcdolphin/heroku-benchserver.git"
      system "git remote add heroku git@#{heroku_git_domain}:#{config[:app]}.git"
      pullres = capture { system "git pull --quiet origin master"}
      pushres = capture { system "git push heroku master --quiet"}
    end
  end
end

Private Instance Methods

action(message) { || ... } click to toggle source
# File lib/herokubench/cli.rb, line 201
def action(message)
  print "#{message}... "
  yield
  puts "done"
end
capture() { || ... } click to toggle source
# File lib/herokubench/cli.rb, line 187
def capture
  results = $stdout = StringIO.new
  yield
  $stdout = STDOUT
  results.close_write
  results.rewind
  return results.read
end
config() click to toggle source
# File lib/herokubench/cli.rb, line 215
def config
  read_config
end
config_file() click to toggle source
# File lib/herokubench/cli.rb, line 211
def config_file
  File.expand_path("~/.herokubench")
end
error(message) click to toggle source
# File lib/herokubench/cli.rb, line 232
def error(message)
  puts "!! #{message}"
  exit 1
end
heroku(command) click to toggle source
# File lib/herokubench/cli.rb, line 207
def heroku(command)
  %x{ env BUNDLE_GEMFILE= heroku #{command} 2>&1 }
end
heroku_git_domain() click to toggle source

heroku_git_domain checks to see if the heroku-accounts plugin is present, and if so, it will set the domain to the one that matches the credentials for the currently set account

# File lib/herokubench/cli.rb, line 246
def heroku_git_domain
  suffix = %x{ git config heroku.account }
  suffix = "com" if suffix.nil? or suffix.strip == ""
  "heroku.#{suffix.strip}"
end
kill_running_dynos() click to toggle source
# File lib/herokubench/cli.rb, line 175
def kill_running_dynos()
  print "\nKilling running dynos"
  result = capture { Heroku::Command.run("ps", ["--app", "#{config[:app]}"]) }
  result.split("\n").each do |line|
    dyno_name = line.scan(/(run.[\d]+)/)
    unless dyno_name.nil? or dyno_name.empty?
      capture {Heroku::Command.run("ps:stop", ["#{dyno_name[0][0]}","--app", "#{config[:app]}"])}
      print '.'
    end
  end
end
kill_running_procs(running_procs) click to toggle source
# File lib/herokubench/cli.rb, line 167
def kill_running_procs(running_procs)
    print "Killing running processes"
    running_procs.keys.each do |pid|
      Process.kill("INT", pid)
      print "."
    end
end
null_dev() click to toggle source

Yeah, we are windows compatible. Because you should be too.

# File lib/herokubench/cli.rb, line 197
def null_dev
  return test(?e, '/dev/null') ? '/dev/null' : 'NUL:'
end
read_config() click to toggle source
# File lib/herokubench/cli.rb, line 219
def read_config
  return {} unless File.exists?(config_file)
  config = YAML.load_file(config_file)
  config.is_a?(Hash) ? config : {}
end
server_path() click to toggle source
# File lib/herokubench/cli.rb, line 237
def server_path
  File.expand_path("../../../server", __FILE__)
end
write_config(config) click to toggle source
# File lib/herokubench/cli.rb, line 225
def write_config(config)
  full_config = read_config.merge(config)
  File.open(config_file, "w") do |file|
    file.puts YAML.dump(full_config)
  end
end