Class: Servolux::Child
- Inherits:
-
Object
- Object
- Servolux::Child
- Defined in:
- lib/servolux/child.rb
Overview
Synopsis
Manage a child process spawned via IO#popen and provide a timeout mechanism to kill the process after some amount time.
Details
Ruby provides the IO#popen method to spawn a child process and return an IO instance connected to the child’s stdin and stdout (with stderr redirected to stdout). The Servolux::Child class adds to this a timeout thread that will signal the child process after some number of seconds. If the child exits cleanly before the timeout expires then no signals are sent to the child.
A list of signals can be provided which will be sent in succession to the child until one of them causes the child to exit. The current Ruby thread suspends for a few seconds to allow each signal to be processed by the child. By default these signals are SIGTERM, SIGQUIT, SIGKILL and the time to wait between signals is four seconds.
The stop
method is used to stop the child process (if running) and to reset the state of the Child instance so that it can be started again. Stopping the Child instance closes the IO between parent and child process.
The wait
method is used to wait for the child process to exit. The Process::Status object is retrieved by the Child and stored as an instance variable. The exitstatus
method (and the other process related methods) will return non-nil values after the wait method is called.
Examples
child = Servolux::Child.new(:command => 'sleep 120', :timeout => 10)
child.start
child.wait
child.timed_out? #=> true
child.signaled? #=> true
child.exitstatus #=> nil
Instance Attribute Summary collapse
-
#command ⇒ Object
Returns the value of attribute command.
-
#io ⇒ Object
readonly
Returns the value of attribute io.
-
#pid ⇒ Object
readonly
Returns the value of attribute pid.
-
#signals ⇒ Object
Returns the value of attribute signals.
-
#suspend ⇒ Object
Returns the value of attribute suspend.
-
#timeout ⇒ Object
Returns the value of attribute timeout.
Instance Method Summary collapse
-
#alive? ⇒ Boolean
Returns
true
if the child process is alive. -
#initialize(opts = {}) {|_self| ... } ⇒ Child
constructor
Create a new Child that will execute and manage the
command
string as a child process. -
#start(mode = 'r') {|IO| ... } ⇒ IO
Runs the
command
string as a subprocess; the subprocess’s standard input and output will be connected to the returned IO object. -
#stop ⇒ Object
Stop the child process if it is alive.
-
#timed_out? ⇒ Boolean
Returns
true
if the child process was killed by the timeout thread. -
#wait(flags = 0) ⇒ Integer?
Waits for the child process to exit and returns its exit status.
Constructor Details
#initialize(opts = {}) {|_self| ... } ⇒ Child
Create a new Child that will execute and manage the command
string as a child process.
69 70 71 72 73 74 75 76 |
# File 'lib/servolux/child.rb', line 69 def initialize( opts = {} ) @command = opts[:command] @timeout = opts[:timeout] @signals = opts[:signals] || %w[TERM QUIT KILL] @suspend = opts[:suspend] || 4 @io = @pid = @status = @thread = @timed_out = nil yield self if block_given? end |
Instance Attribute Details
#command ⇒ Object
Returns the value of attribute command.
42 43 44 |
# File 'lib/servolux/child.rb', line 42 def command @command end |
#io ⇒ Object (readonly)
Returns the value of attribute io.
46 47 48 |
# File 'lib/servolux/child.rb', line 46 def io @io end |
#pid ⇒ Object (readonly)
Returns the value of attribute pid.
47 48 49 |
# File 'lib/servolux/child.rb', line 47 def pid @pid end |
#signals ⇒ Object
Returns the value of attribute signals.
44 45 46 |
# File 'lib/servolux/child.rb', line 44 def signals @signals end |
#suspend ⇒ Object
Returns the value of attribute suspend.
45 46 47 |
# File 'lib/servolux/child.rb', line 45 def suspend @suspend end |
#timeout ⇒ Object
Returns the value of attribute timeout.
43 44 45 |
# File 'lib/servolux/child.rb', line 43 def timeout @timeout end |
Instance Method Details
#alive? ⇒ Boolean
Returns true
if the child process is alive. Returns nil
if the child process has not been started.
151 152 153 154 155 156 157 |
# File 'lib/servolux/child.rb', line 151 def alive? return if @io.nil? Process.kill(0, @pid) true rescue Errno::ESRCH, Errno::ENOENT false end |
#start(mode = 'r') {|IO| ... } ⇒ IO
Runs the command
string as a subprocess; the subprocess’s standard input and output will be connected to the returned IO object. The default mode for the new file object is “r”, but mode may be set to any of the modes listed in the description for class IO.
If a block is given, Ruby will run the command
as a child connected to Ruby with a pipe. Ruby’s end of the pipe will be passed as a parameter to the block. In this case the value of the block is returned.
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/servolux/child.rb', line 95 def start( mode = 'r', &block ) start_timeout_thread if @timeout @io = IO::popen @command, mode @pid = @io.pid @status = nil return block.call(@io) unless block.nil? @io end |
#stop ⇒ Object
Stop the child process if it is alive. A sequence of signals
are sent to the process until it dies with SIGKILL being the signal of last resort.
After this method returns, the IO pipe to the child will be closed and the stored child PID is set to nil
. The start
method can be safely called again.
116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/servolux/child.rb', line 116 def stop unless @thread.nil? t, @thread = @thread, nil t[:stop] = true t.wakeup.join if t.status end kill if alive? @io.close rescue nil @io = nil self end |
#timed_out? ⇒ Boolean
Returns true
if the child process was killed by the timeout thread.
163 164 165 |
# File 'lib/servolux/child.rb', line 163 def timed_out? @timed_out end |
#wait(flags = 0) ⇒ Integer?
Waits for the child process to exit and returns its exit status. The global variable $? is set to a Process::Status object containing information on the child process.
139 140 141 142 143 144 |
# File 'lib/servolux/child.rb', line 139 def wait( flags = 0 ) return if @io.nil? Process.wait(@pid, flags) @status = $? exitstatus end |