class Child
Represents a running child process from the point of view of the parent container.
Nested
Definitions
def self.fork(**options)
Fork a child process appropriate for a container.
Signature
-
returns
Process
Implementation
def self.fork(**options)
# $stderr.puts fork: caller
self.new(**options) do |process|
::Process.fork do
# We use `Thread.current.raise(...)` so that exceptions are filtered through `Thread.handle_interrupt` correctly.
Signal.trap(:INT) {::Thread.current.raise(Interrupt)}
Signal.trap(:TERM) {::Thread.current.raise(Terminate)}
Signal.trap(:HUP) {::Thread.current.raise(Restart)}
# This could be a configuration option:
::Thread.handle_interrupt(SignalException => :immediate) do
yield Instance.for(process)
rescue Interrupt
# Graceful exit.
rescue Exception => error
Console.error(self, error)
exit!(1)
end
end
end
end
def initialize(name: nil)
Initialize the process.
Signature
-
parameter
name
String
The name to use for the child process.
Implementation
def initialize(name: nil)
super()
@name = name
@status = nil
@pid = nil
@pid = yield(self)
# The parent process won't be writing to the channel:
self.close_write
end
def name= value
Set the name of the process.
Invokes ::Process.setproctitle
if invoked in the child process.
Implementation
def name= value
@name = value
# If we are the child process:
::Process.setproctitle(@name) if @pid.nil?
end
attr :name
The name of the process.
Signature
-
attribute
String
attr :pid
Signature
-
attribute
Integer
The process identifier.
def inspect
A human readable representation of the process.
Signature
-
returns
String
Implementation
def inspect
"\#<#{self.class} name=#{@name.inspect} status=#{@status.inspect} pid=#{@pid.inspect}>"
end
def close
Invoke #terminate!
and then #wait
for the child process to exit.
Implementation
def close
self.terminate!
self.wait
ensure
super
end
def interrupt!
Send SIGINT
to the child process.
Implementation
def interrupt!
unless @status
::Process.kill(:INT, @pid)
end
end
def terminate!
Send SIGTERM
to the child process.
Implementation
def terminate!
unless @status
::Process.kill(:TERM, @pid)
end
end
def restart!
Send SIGHUP
to the child process.
Implementation
def restart!
unless @status
::Process.kill(:HUP, @pid)
end
end
def wait
- asynchronous
Wait for the child process to exit.
Signature
- asynchronous
This method may block.
-
returns
::Process::Status
The process exit status.
Implementation
def wait
if @pid && @status.nil?
Console.debug(self, "Waiting for process to exit...", pid: @pid)
_, @status = ::Process.wait2(@pid, ::Process::WNOHANG)
while @status.nil?
sleep(0.1)
_, @status = ::Process.wait2(@pid, ::Process::WNOHANG)
if @status.nil?
Console.warn(self) {"Process #{@pid} is blocking, has it exited?"}
end
end
end
Console.debug(self, "Process exited.", pid: @pid, status: @status)
return @status
end