Class for spawning Rack applications.
Spawn an instance of the given Rack application. When successful, an Application object will be returned, which represents the spawned application.
Accepts the same options as Railz::ApplicationSpawner#initialize.
Raises:
AppInitError: The Rack application raised an exception or called exit() during startup.
SystemCallError, IOError, SocketError: Something went wrong.
# File lib/phusion_passenger/rack/application_spawner.rb, line 54 54: def spawn_application(app_root, options = {}) 55: options = sanitize_spawn_options(options) 56: 57: a, b = UNIXSocket.pair 58: pid = safe_fork(self.class.to_s, true) do 59: a.close 60: 61: file_descriptors_to_leave_open = [0, 1, 2, b.fileno] 62: NativeSupport.close_all_file_descriptors(file_descriptors_to_leave_open) 63: close_all_io_objects_for_fds(file_descriptors_to_leave_open) 64: 65: run(MessageChannel.new(b), app_root, options) 66: end 67: b.close 68: Process.waitpid(pid) rescue nil 69: 70: channel = MessageChannel.new(a) 71: unmarshal_and_raise_errors(channel, !!options["print_exceptions"], "rack") 72: 73: # No exception was raised, so spawning succeeded. 74: pid, socket_name, socket_type = channel.read 75: if pid.nil? 76: raise IOError, "Connection closed" 77: end 78: owner_pipe = channel.recv_io 79: return Application.new(@app_root, pid, socket_name, 80: socket_type, owner_pipe) 81: end
# File lib/phusion_passenger/rack/application_spawner.rb, line 141 141: def load_rack_app 142: # Load Rack inside the spawned child process so that the spawn manager 143: # itself doesn't preload Rack. This is necessary because some broken 144: # Rails apps explicitly specify a Rack version as dependency. 145: require 'rack' 146: rackup_code = ::File.read("config.ru") 147: eval("Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, "config.ru") 148: end
# File lib/phusion_passenger/rack/application_spawner.rb, line 84 84: def run(channel, app_root, options) 85: $0 = "Rack: #{app_root}" 86: app = nil 87: success = report_app_init_status(channel) do 88: ENV['RACK_ENV'] = options["environment"] 89: ENV['RAILS_ENV'] = options["environment"] 90: if options["base_uri"] && options["base_uri"] != "/" 91: ENV['RACK_BASE_URI'] = options["base_uri"] 92: ENV['RAILS_RELATIVE_URL_ROOT'] = options["base_uri"] 93: end 94: Dir.chdir(app_root) 95: if options["environment_variables"] 96: set_passed_environment_variables(options["environment_variables"]) 97: end 98: if options["lower_privilege"] 99: lower_privilege('config.ru', options["lowest_user"]) 100: end 101: # Make sure RubyGems uses any new environment variable values 102: # that have been set now (e.g. $HOME, $GEM_HOME, etc) and that 103: # it is able to detect newly installed gems. 104: Gem.clear_paths 105: setup_bundler_support 106: app = load_rack_app 107: end 108: 109: if success 110: reader, writer = IO.pipe 111: begin 112: handler = RequestHandler.new(reader, app, options) 113: channel.write(Process.pid, handler.socket_name, 114: handler.socket_type) 115: channel.send_io(writer) 116: writer.close 117: channel.close 118: 119: PhusionPassenger.call_event(:starting_worker_process) 120: handler.main_loop 121: ensure 122: channel.close rescue nil 123: writer.close rescue nil 124: handler.cleanup rescue nil 125: PhusionPassenger.call_event(:stopping_worker_process) 126: end 127: end 128: end
# File lib/phusion_passenger/rack/application_spawner.rb, line 130 130: def set_passed_environment_variables(encoded_environment_variables) 131: env_vars_string = encoded_environment_variables.unpack("m").first 132: # Prevent empty string as last item from b0rking the Hash[...] statement. 133: # See comment in Hooks.cpp (sendHeaders) for details. 134: env_vars_string << "_\00__" 135: env_vars = Hash[*env_vars_string.split("\00"")] 136: env_vars.each_pair do |key, value| 137: ENV[key] = value 138: end 139: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.