class PhusionPassenger::Rack::ApplicationSpawner

Spawning of Rack applications.

def self.load_rack_app

def self.load_rack_app
	# Load Rack inside the spawned child process so that the spawn manager
	# itself doesn't preload Rack. This is necessary because some broken
	# Rails apps explicitly specify a Rack version as dependency.
	require 'rack'
	rackup_file = ENV["RACKUP_FILE"] || "config.ru"
	rackup_code = ::File.open(rackup_file, 'rb') do |f|
		f.read
	end
	eval("Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, rackup_file)
end

def self.spawn_application(options = {})

- SystemCallError, IOError, SocketError: Something went wrong.
exit() during startup.
- AppInitError: The Rack application raised an exception or called
Raises:

Accepts the same options as SpawnManager#spawn_application.

application.
AppProcess object will be returned, which represents the spawned
Spawn an instance of the given Rack application. When successful, an
def self.spawn_application(options = {})
	options = sanitize_spawn_options(options)
	
	a, b = UNIXSocket.pair
	pid = safe_fork(self.class.to_s, true) do
		a.close
		
		file_descriptors_to_leave_open = [0, 1, 2, b.fileno]
		NativeSupport.close_all_file_descriptors(file_descriptors_to_leave_open)
		close_all_io_objects_for_fds(file_descriptors_to_leave_open)
		
		channel = MessageChannel.new(b)
		app = nil
		success = report_app_init_status(channel) do
			prepare_app_process('config.ru', options)
			app = load_rack_app
			after_loading_app_code(options)
		end
		if success
			start_request_handler(channel, app, false, options)
		end
	end
	b.close
	Process.waitpid(pid) rescue nil
	
	channel = MessageChannel.new(a)
	unmarshal_and_raise_errors(channel, options["print_exceptions"], "rack")
	
	# No exception was raised, so spawning succeeded.
	return AppProcess.read_from_channel(channel)
end

def self.start_request_handler(channel, app, forked, options)

def self.start_request_handler(channel, app, forked, options)
	app_root = options["app_root"]
	$0 = "Rack: #{options['app_group_name']}"
	reader, writer = IO.pipe
	begin
		reader.close_on_exec!
		
		handler = RequestHandler.new(reader, app, options)
		app_process = AppProcess.new(app_root, Process.pid, writer,
			handler.server_sockets)
		app_process.write_to_channel(channel)
		writer.close
		channel.close
		
		before_handling_requests(forked, options)
		handler.main_loop
	ensure
		channel.close rescue nil
		writer.close rescue nil
		handler.cleanup rescue nil
		after_handling_requests
	end
end

def before_fork # :nodoc:

:nodoc:
Overrided method.
def before_fork # :nodoc:
	if GC.copy_on_write_friendly?
		# Garbage collect now so that the child process doesn't have to
		# do that (to prevent making pages dirty).
		GC.start
	end
end

def handle_spawn_application(client, *options)

def handle_spawn_application(client, *options)
	options = sanitize_spawn_options(Hash[*options])
	a, b = UNIXSocket.pair
	safe_fork('application', true) do
		begin
			a.close
			client.close
			options = @options.merge(options)
			self.class.send(:start_request_handler, MessageChannel.new(b),
				@app, true, options)
		rescue SignalException => e
			if e.message != AbstractRequestHandler::HARD_TERMINATION_SIGNAL &&
			   e.message != AbstractRequestHandler::SOFT_TERMINATION_SIGNAL
				raise
			end
		end
	end
	
	b.close
	worker_channel = MessageChannel.new(a)
	app_process = AppProcess.read_from_channel(worker_channel)
	app_process.write_to_channel(client)
ensure
	a.close if a
	b.close if b && !b.closed?
	app_process.close if app_process
end

def initialize(options)

See SpawnManager#spawn_application for information about the options.

- 'app_root'
The following options are accepted:
def initialize(options)
	super()
	@options          = sanitize_spawn_options(options)
	@app_root         = @options["app_root"]
	@canonicalized_app_root = canonicalize_path(@app_root)
	self.max_idle_time = DEFAULT_APP_SPAWNER_MAX_IDLE_TIME
	define_message_handler(:spawn_application, :handle_spawn_application)
end

def initialize_server # :nodoc:

:nodoc:
Overrided method.
def initialize_server # :nodoc:
	report_app_init_status(MessageChannel.new(@owner_socket)) do
		$0 = "Passenger ApplicationSpawner: #{@options['app_group_name']}"
		prepare_app_process('config.ru', @options)
		@app = self.class.send(:load_rack_app)
		after_loading_app_code(@options)
	end
end

def spawn_application(options = {})

- ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
- AbstractServer::ServerNotStarted: The ApplicationSpawner server hasn't already been started.
Raises:

+options+ will be passed to the request handler's constructor.

will be returned, which represents the spawned Rack application.
Spawns an instance of the Rack application. When successful, an AppProcess object
def spawn_application(options = {})
	connect do |channel|
		channel.write("spawn_application", *options.to_a.flatten)
		return AppProcess.read_from_channel(channel)
	end
rescue SystemCallError, IOError, SocketError => e
	raise Error, "The application spawner server exited unexpectedly: #{e}"
end

def start

- ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
or called exit() during startup.
- AppInitError: The Rack application raised an exception
May raise these additional exceptions:

Overrided from AbstractServer#start.
def start
	super
	begin
		channel = MessageChannel.new(@owner_socket)
		unmarshal_and_raise_errors(channel, @options["print_exceptions"])
	rescue IOError, SystemCallError, SocketError => e
		stop if started?
		raise Error, "The application spawner server exited unexpectedly: #{e}"
	rescue
		stop if started?
		raise
	end
end