class Servolux::Prefork::Worker


worker.
the block or module supplied to the pre-forking pool that created the
between the parent and the child. Each worker instance is extended with
The worker encapsulates the forking of the child process and communication

def alive?


Always returns +nil+ when called from the child process.

process has not been started.
Returns +true+ if the child process is alive. Returns +nil+ if the child
def alive?
  return if @piper.nil?
  @piper.alive?
end

def child


signals and communication with the parent.
user supplied "execute" code in a loop, and takes care of handling
This code should only be executed in the child process. It wraps the
def child
  @thread = Thread.current
  # if we get a HUP signal, then tell the parent process to stop this
  # child process and start a new one to replace it
  Signal.trap('HUP') {
    @piper.puts START rescue nil
    @thread.wakeup
  }
  before_executing if self.respond_to? :before_executing
  :wait until @piper.gets == START
  loop {
    signal = @piper.gets(ERROR)
    case signal
    when HEARTBEAT
      execute
      @piper.puts HEARTBEAT
    when HALT
      break
    when ERROR
      raise Timeout,
            "Parent did not respond in a timely fashion. Timeout is set to #{@prefork.timeout} seconds."
    else
      raise UnknownSignal,
            "Child received unknown signal: #{signal.inspect}"
    end
  }
  after_executing if self.respond_to? :after_executing
rescue Exception => err
  @piper.puts err rescue nil
ensure
  @piper.close
  exit!
end

def initialize( prefork )


Create a new worker that belongs to the _prefork_ pool.
def initialize( prefork )
  @prefork = prefork
  @thread = nil
  @piper = nil
  @error = nil
end

def kill( signal = 'TERM' )


'TERM'. This method will return immediately.
Send this given _signal_ to the child process. The default signal is
def kill( signal = 'TERM' )
  return if @piper.nil?
  @piper.signal signal
rescue Errno::ESRCH, Errno::ENOENT
  return nil
end

def parent


This code should only be executed in the parent process.
def parent
  @thread = Thread.new {
    response = nil
    begin
      @piper.puts START
      Thread.current[:stop] = false
      loop {
        break if Thread.current[:stop]
        @piper.puts HEARTBEAT
        response = @piper.gets(ERROR)
        break if Thread.current[:stop]
        case response
        when HEARTBEAT; next
        when START; break
        when ERROR
          raise Timeout,
                "Child did not respond in a timely fashion. Timeout is set to #{@prefork.timeout} seconds."
        when Exception
          raise response
        else
          raise UnknownResponse,
                "Child returned unknown response: #{response.inspect}"
        end
      }
    rescue Exception => err
      @error = err
    ensure
      @piper.timeout = 0
      @piper.puts HALT rescue nil
      @piper.close
      self.start if START == response
    end
  }
  Thread.pass until @thread[:stop] == false
end

def start


by the user to the prefork pool will be executed in the child process.
Start this worker. A new process will be forked, and the code supplied
def start
  @error = nil
  @piper = ::Servolux::Piper.new('rw', :timeout => @prefork.timeout)
  parent if @piper.parent?
  child if @piper.child?
  self
end

def stop


after calling +stop+ if your code needs to know when the child exits.
without waiting for the child process to exit. Use the +wait+ method
signal is sent to the child process. This method will return immediately
Stop this worker. The internal worker thread is stopped and a 'HUP'
def stop
  return if @thread.nil? or @piper.nil? or @piper.child?
  @thread[:stop] = true
  @thread.wakeup
  Thread.pass until !@thread.status
  kill 'HUP'
  @thread = nil
  self
end

def wait


forked.
called from the child process or if the child process has not yet been
Wait for the child process to exit. This method returns immediately when
def wait
  return if @piper.nil? or @piper.child?
  Process.wait(@piper.pid, Process::WNOHANG|Process::WUNTRACED)
end