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