class Slugrunner::Runner
Attributes
bind_delay[RW]
extra_env[RW]
ping_interval[RW]
ping_url[RW]
shell[RW]
Public Class Methods
new(slug, process_type, instance_number)
click to toggle source
# File lib/slugrunner/runner.rb, line 18 def initialize(slug, process_type, instance_number) @slug = slug @process_type = process_type @ping = false @bind_delay = 0 @ping_url = nil @ping_interval = 0 @alive = false @shell = false @extra_env = [] @hostname = "#{@process_type}.#{instance_number}" end
Public Instance Methods
run()
click to toggle source
# File lib/slugrunner/runner.rb, line 31 def run Dir.mktmpdir do |tmpdir| logger("Scratch directory -> #{tmpdir}") @slug_dir = tmpdir @ping = true if !@ping_url.nil? && @ping_interval > 0 download_and_run return 0 end rescue => e logger("Error: #{e}") return 1 end
Private Instance Methods
check_port()
click to toggle source
# File lib/slugrunner/runner.rb, line 72 def check_port port = (ENV['PORT'] || '0').to_i return true if @bind_delay == 0 || port == 0 start_ts = Time.now stop_ts = start_ts.to_i + @bind_delay while Time.now.to_i < stop_ts return true if port_open?(port) end logger("Port hasn't been open after #{@bind_delay} seconds.") false end
download_and_run()
click to toggle source
# File lib/slugrunner/runner.rb, line 46 def download_and_run notify(:setup) if @ping fetch_slug proc_command = if @shell '/bin/bash' else extract_command_from_procfile || extract_command_from_release end fail "Couldn't find command for process type #{@process_type}" unless proc_command command = prepare_env(proc_command) @child = fork { exec(command) } trap_signals @alive = check_port kill_child unless @alive start_ping if @ping Process.waitpid(@child, 0) @alive = false notify(:stop) if @ping end
extract_command_from_procfile()
click to toggle source
# File lib/slugrunner/runner.rb, line 153 def extract_command_from_procfile return nil unless File.exists?("#{@slug_dir}/Procfile") procfile = YAML.load_file("#{@slug_dir}/Procfile") return procfile[@process_type] if procfile.key?(@process_type) end
extract_command_from_release()
click to toggle source
# File lib/slugrunner/runner.rb, line 160 def extract_command_from_release return nil unless File.exists?("#{@slug_dir}/.release") release = YAML.load_file("#{@slug_dir}/.release") return release['default_process_types'][@process_type] if release['default_process_types'].key?(@process_type) end
fetch_slug()
click to toggle source
# File lib/slugrunner/runner.rb, line 143 def fetch_slug if @slug =~ /^http/ `curl -L -s "#{@slug}" | tar -zxC #{@slug_dir}` else `tar zx -C #{@slug_dir} -f #{@slug}` end fail 'Failed to decompress slug' if $?.exitstatus != 0 end
kill_child()
click to toggle source
# File lib/slugrunner/runner.rb, line 110 def kill_child if @child logger("Killing process #{@child} with SIGKILL.") Process.kill('KILL', @child) end end
logger(str)
click to toggle source
# File lib/slugrunner/runner.rb, line 129 def logger(str) puts("[slugrunner] #{str}") end
notify(state)
click to toggle source
# File lib/slugrunner/runner.rb, line 117 def notify(state) # these are fire and forget for now ap = "state=#{state}&hostname=#{@hostname}" if @ping_url =~ /\?/ open("#{@ping_url}&#{ap}") else open("#{@ping_url}?#{ap}") end rescue => e logger("Failed to notify #{@ping_url}: #{e}") end
port_open?(port)
click to toggle source
# File lib/slugrunner/runner.rb, line 133 def port_open?(port) # no need for timeout as we always connect to localhost s = TCPSocket.new('localhost', port) return true rescue return false ensure s.close if s end
prepare_env(cmd)
click to toggle source
# File lib/slugrunner/runner.rb, line 167 def prepare_env(cmd) blob = <<-eos exec env - bash -c ' cd #{@slug_dir} export HOME=#{@slug_dir} export APP_DIR=#{@slug_dir} export HOSTNAME="#{@hostname}" export SLUGRUNNER=1 export SLUG_ENV=1 PORT=#{ENV['PORT'] || 0} for file in .profile.d/*; do source $file; done eos @extra_env.each do |e| pair = e.split(/=/, 2) next unless pair.length == 2 escaped = pair.map { |n| Shellwords.escape(n) } blob += "export #{escaped[0]}=#{escaped[1]}\n" end blob += "exec #{cmd}'" blob end
start_ping()
click to toggle source
# File lib/slugrunner/runner.rb, line 87 def start_ping return unless @alive notify(:start) Thread.new do while @alive sleep(@ping_interval) notify(:update) end end end
trap_signals()
click to toggle source
# File lib/slugrunner/runner.rb, line 101 def trap_signals %w{INT HUP TERM QUIT}.each do |sig| Signal.trap(sig) do logger("Forwarding #{sig} to #{@child}") Process.kill(sig, @child) end end end