Async::ContainerSourceAsyncContainerProcess

class Process

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)
	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)}
			
			begin
				yield Instance.for(process)
			rescue Interrupt
				# Graceful exit.
			rescue Exception => error
				Console.logger.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

def to_s

A human readable representation of the process.

Signature

returns String

Implementation

def to_s
	"\#<#{self.class} #{@name}>"
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 wait

Wait for the child process to exit.

Signature

returns ::Process::Status

The process exit status.

Implementation

def wait
	if @pid && @status.nil?
		_, @status = ::Process.wait2(@pid, ::Process::WNOHANG)
		
		if @status.nil?
			sleep(0.01)
			_, @status = ::Process.wait2(@pid, ::Process::WNOHANG)
		end
		
		if @status.nil?
			Console.logger.warn(self) {"Process #{@pid} is blocking, has it exited?"}
			_, @status = ::Process.wait2(@pid)
		end
	end
	
	return @status
end