Parent

Namespace

Foreman::Engine

Constants

HANDLED_SIGNALS

The signals that the engine cares about.

Attributes

env[R]
options[R]
processes[R]

Public Class Methods

new(options={}) click to toggle source

Create an Engine for running processes

@param [Hash] options

@option options [String] :formation (all=1) The process formation to use @option options [Fixnum] :port (5000) The base port to assign to processes @option options [String] :root (Dir.pwd) The root directory from which to run processes

# File lib/foreman/engine.rb, line 28
def initialize(options={})
  @options = options.dup

  @options[:formation] ||= (options[:concurrency] || "all=1")
  @options[:timeout] ||= 5

  @env       = {}
  @mutex     = Mutex.new
  @names     = {}
  @processes = []
  @running   = {}
  @readers   = {}

  # Self-pipe for deferred signal-handling (ala djb: http://cr.yp.to/docs/selfpipe.html)
  reader, writer       = create_pipe
  reader.close_on_exec = true if reader.respond_to?(:close_on_exec)
  writer.close_on_exec = true if writer.respond_to?(:close_on_exec)
  @selfpipe            = { :reader => reader, :writer => writer }

  # Set up a global signal queue
  # http://blog.rubybestpractices.com/posts/ewong/016-Implementing-Signal-Handlers.html
  Thread.main[:signal_queue] = []
end

Public Instance Methods

base_port() click to toggle source

Get the base port for this foreman instance

@returns [Fixnum] port The base port

# File lib/foreman/engine.rb, line 272
def base_port
  (options[:port] || env["PORT"] || ENV["PORT"] || 5000).to_i
end
clear() click to toggle source

Clear the processes registered to this Engine

# File lib/foreman/engine.rb, line 150
def clear
  @names     = {}
  @processes = []
end
each_process() click to toggle source

Yield each Process in order

# File lib/foreman/engine.rb, line 239
def each_process
  process_names.each do |name|
    yield name, process(name)
  end
end
environment() click to toggle source

deprecated

# File lib/foreman/engine.rb, line 277
def environment
  env
end
formation() click to toggle source

Get the process formation

@returns [Fixnum] The formation count for the specified process

# File lib/foreman/engine.rb, line 215
def formation
  @formation ||= parse_formation(options[:formation])
end
handle_hangup() click to toggle source

Handle a HUP signal

# File lib/foreman/engine.rb, line 127
def handle_hangup
  puts "SIGHUP received"
  terminate_gracefully
end
handle_interrupt() click to toggle source

Handle an INT signal

# File lib/foreman/engine.rb, line 120
def handle_interrupt
  puts "SIGINT received"
  terminate_gracefully
end
handle_signal(sig) click to toggle source

Invoke the real handler for signal sig. This shouldn’t be called directly by signal handlers, as it might invoke code which isn’t re-entrant.

@param [Symbol] sig the name of the signal to be handled

# File lib/foreman/engine.rb, line 98
def handle_signal(sig)
  case sig
  when :TERM
    handle_term_signal
  when :INT
    handle_interrupt
  when :HUP
    handle_hangup
  else
    system "unhandled signal #{sig}"
  end
end
handle_term_signal() click to toggle source

Handle a TERM signal

# File lib/foreman/engine.rb, line 113
def handle_term_signal
  puts "SIGTERM received"
  terminate_gracefully
end
kill_children(signal="SIGTERM") click to toggle source

Send a signal to all processes started by this Engine

@param [String] signal The signal to send to each process

# File lib/foreman/engine.rb, line 179
def kill_children(signal="SIGTERM")
  if Foreman.windows?
    @running.each do |pid, (process, index)|
      system "sending #{signal} to #{name_for(pid)} at pid #{pid}"
      begin
        Process.kill(signal, pid)
      rescue Errno::ESRCH, Errno::EPERM
      end
    end
  else
    begin
      Process.kill signal, *@running.keys unless @running.empty?
    rescue Errno::ESRCH, Errno::EPERM
    end
  end
end
killall(signal="SIGTERM") click to toggle source

Send a signal to the whole process group.

@param [String] signal The signal to send

# File lib/foreman/engine.rb, line 200
def killall(signal="SIGTERM")
  if Foreman.windows?
    kill_children(signal)
  else
    begin
      Process.kill "-#{signal}", Process.pid
    rescue Errno::ESRCH, Errno::EPERM
    end
  end
end
load_env(filename) click to toggle source

Load a .env file into the env for this Engine

@param [String] filename A .env file to load into the environment

# File lib/foreman/engine.rb, line 171
def load_env(filename)
  @env.update Dotenv::Environment.new(filename)
end
load_procfile(filename) click to toggle source

Register processes by reading a Procfile

@param [String] filename A Procfile from which to read processes to register

# File lib/foreman/engine.rb, line 159
def load_procfile(filename)
  options[:root] ||= File.dirname(filename)
  Foreman::Procfile.new(filename).entries do |name, command|
    register name, command, :cwd => options[:root]
  end
  self
end
notice_signal() click to toggle source

Wake the main thread up via the selfpipe when there’s a signal

# File lib/foreman/engine.rb, line 84
def notice_signal
  @selfpipe[:writer].write_nonblock( '.' )
rescue Errno::EAGAIN
  # Ignore writes that would block
rescue Errno::EINT
  # Retry if another signal arrived while writing
  retry
end
port_for(process, instance, base=nil) click to toggle source

Get the port for a given process and offset

@param [Foreman::Process] process A Process associated with this engine @param [Fixnum] instance The instance of the process

@returns [Fixnum] port The port to use for this instance of this process

# File lib/foreman/engine.rb, line 260
def port_for(process, instance, base=nil)
  if base
    base + (@processes.index(process.process) * 100) + (instance - 1)
  else
    base_port + (@processes.index(process) * 100) + (instance - 1)
  end
end
process(name) click to toggle source

Get the Process for a specifid name

@param [String] name The process name

@returns [Foreman::Process] The Process for the specified name

# File lib/foreman/engine.rb, line 233
def process(name)
  @names.invert[name]
end
process_names() click to toggle source

List the available process names

@returns [Array] A list of process names

# File lib/foreman/engine.rb, line 223
def process_names
  @processes.map { |p| @names[p] }
end
register(name, command, options={}) click to toggle source

Register a process to be run by this Engine

@param [String] name A name for this process @param [String] command The command to run @param [Hash] options

@option options [Hash] :env A custom environment for this process

# File lib/foreman/engine.rb, line 140
def register(name, command, options={})
  options[:env] ||= env
  options[:cwd] ||= File.dirname(command.split(" ").first)
  process = Foreman::Process.new(command, options)
  @names[process] = name
  @processes << process
end
register_signal_handlers() click to toggle source

Set up deferred signal handlers

# File lib/foreman/engine.rb, line 66
def register_signal_handlers
  HANDLED_SIGNALS.each do |sig|
    if ::Signal.list.include? sig.to_s
      trap(sig) { Thread.main[:signal_queue] << sig ; notice_signal }
    end
  end
end
restore_default_signal_handlers() click to toggle source

Unregister deferred signal handlers

# File lib/foreman/engine.rb, line 76
def restore_default_signal_handlers
  HANDLED_SIGNALS.each do |sig|
    trap(sig, :DEFAULT) if ::Signal.list.include? sig.to_s
  end
end
root() click to toggle source

Get the root directory for this Engine

@returns [String] The root directory

# File lib/foreman/engine.rb, line 249
def root
  File.expand_path(options[:root] || Dir.pwd)
end
start() click to toggle source

Start the processes registered to this Engine

# File lib/foreman/engine.rb, line 54
def start
  register_signal_handlers
  startup
  spawn_processes
  watch_for_output
  sleep 0.1
  watch_for_termination { terminate_gracefully }
  shutdown
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.