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)
-
- (Object) command
Returns the value of attribute command.
-
- (Object) io
readonly
Returns the value of attribute io.
-
- (Object) pid
readonly
Returns the value of attribute pid.
-
- (Object) signals
Returns the value of attribute signals.
-
- (Object) suspend
Returns the value of attribute suspend.
-
- (Object) timeout
Returns the value of attribute timeout.
Instance Method Summary (collapse)
-
- (Boolean) alive?
Returns true if the child process is alive.
-
- (Child) initialize(opts = {}) {|_self| ... }
constructor
Create a new Child that will execute and manage the command string as a child process.
-
- (IO) start(mode = 'r') {|IO| ... }
Runs the command string as a subprocess; the subprocess???s standard input and output will be connected to the returned IO object.
-
- (Object) stop
Stop the child process if it is alive.
-
- (Boolean) timed_out?
Returns true if the child process was killed by the timeout thread.
-
- (Integer?) wait(flags = 0)
Waits for the child process to exit and returns its exit status.
Constructor Details
- (Child) initialize(opts = {}) {|_self| ... }
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.fetch(:command, nil) @timeout = opts.fetch(:timeout, nil) @signals = opts.fetch(:signals, %w[TERM QUIT KILL]) @suspend = opts.fetch(:suspend, 4) @io = @pid = @status = @thread = @timed_out = nil yield self if block_given? end |
Instance Attribute Details
- (Object) command
Returns the value of attribute command
42 43 44 |
# File 'lib/servolux/child.rb', line 42 def command @command end |
- (Object) io (readonly)
Returns the value of attribute io
46 47 48 |
# File 'lib/servolux/child.rb', line 46 def io @io end |
- (Object) pid (readonly)
Returns the value of attribute pid
47 48 49 |
# File 'lib/servolux/child.rb', line 47 def pid @pid end |
- (Object) signals
Returns the value of attribute signals
44 45 46 |
# File 'lib/servolux/child.rb', line 44 def signals @signals end |
- (Object) suspend
Returns the value of attribute suspend
45 46 47 |
# File 'lib/servolux/child.rb', line 45 def suspend @suspend end |
- (Object) timeout
Returns the value of attribute timeout
43 44 45 |
# File 'lib/servolux/child.rb', line 43 def timeout @timeout end |
Instance Method Details
- (Boolean) alive?
Returns true if the child process is alive. Returns nil if the child process has not been started.
162 163 164 165 166 167 168 169 |
# File 'lib/servolux/child.rb', line 162 def alive? return if @io.nil? wait(Process::WNOHANG|Process::WUNTRACED) Process.kill(0, @pid) true rescue Errno::ESRCH, Errno::ENOENT false end |
- (IO) start(mode = 'r') {|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 |
- (Object) stop
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 |
- (Boolean) timed_out?
Returns true if the child process was killed by the timeout thread.
175 176 177 |
# File 'lib/servolux/child.rb', line 175 def timed_out? @timed_out end |
- (Integer?) wait(flags = 0)
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.
You can get more information about how the child status exited by calling the following methods on the piper instance:
* coredump?
* exited?
* signaled?
* stopped?
* success?
* exitstatus
* stopsig
* termsig
151 152 153 154 155 |
# File 'lib/servolux/child.rb', line 151 def wait( flags = 0 ) return if @io.nil? _, @status = Process.wait2(@pid, flags) unless @status exitstatus end |