Class | PhusionPassenger::Railz::ApplicationSpawner |
In: |
lib/phusion_passenger/railz/application_spawner.rb
|
Parent: | AbstractServer |
This class is capable of spawning instances of a single Ruby on Rails application. It does so by preloading as much of the application‘s code as possible, then creating instances of the application using what is already preloaded. This makes it spawning application instances very fast, except for the first spawn.
Use multiple instances of ApplicationSpawner if you need to spawn multiple different Ruby on Rails applications.
Note: ApplicationSpawner may only be started asynchronously with AbstractServer#start. Starting it synchronously with AbstractServer#start_synchronously has not been tested.
ROOT_UID | = | 0 | The user ID of the root user. | |
ROOT_GID | = | 0 | The group ID of the root user. |
app_root | [R] | The application root of this spawner. |
app_root is the root directory of this application, i.e. the directory that contains ‘app/’, ‘public/’, etc. If given an invalid directory, or a directory that doesn‘t appear to be a Rails application root directory, then an InvalidPath will be raised.
Additional options are:
If that user doesn‘t exist on the system, or if that user is root, then ApplicationSpawner will attempt to switch to the username given by lowest_user (and to the default group of that user). If lowest_user doesn‘t exist either, or if switching user failed (because the current process does not have the privilege to do so), then ApplicationSpawner will continue without reporting an error.
All other options will be passed on to RequestHandler.
# File lib/phusion_passenger/railz/application_spawner.rb, line 102 102: def initialize(app_root, options = {}) 103: super() 104: @app_root = app_root 105: @canonicalized_app_root = canonicalize_path(app_root) 106: @options = sanitize_spawn_options(options) 107: @lower_privilege = @options["lower_privilege"] 108: @lowest_user = @options["lowest_user"] 109: @environment = @options["environment"] 110: @encoded_environment_variables = @options["environment_variables"] 111: @base_uri = @options["base_uri"] if @options["base_uri"] && @options["base_uri"] != "/" 112: @print_exceptions = @options["print_exceptions"] 113: self.max_idle_time = DEFAULT_APP_SPAWNER_MAX_IDLE_TIME 114: assert_valid_app_root(@app_root) 115: define_message_handler(:spawn_application, :handle_spawn_application) 116: end
Spawn an instance of the RoR application. When successful, an Application object will be returned, which represents the spawned RoR application.
Raises:
# File lib/phusion_passenger/railz/application_spawner.rb, line 124 124: def spawn_application 125: server.write("spawn_application") 126: pid, socket_name, socket_type = server.read 127: if pid.nil? 128: raise IOError, "Connection closed" 129: end 130: owner_pipe = server.recv_io 131: return Application.new(@app_root, pid, socket_name, 132: socket_type, owner_pipe) 133: rescue SystemCallError, IOError, SocketError => e 134: raise Error, "The application spawner server exited unexpectedly: #{e}" 135: end
Spawn an instance of the RoR application. When successful, an Application object will be returned, which represents the spawned RoR application.
Unlike spawn_application, this method may be called even when the ApplicationSpawner server isn‘t started. This allows one to spawn a RoR application without preloading any source files.
This method may only be called if no Rails framework has been loaded in the current Ruby VM.
Raises:
# File lib/phusion_passenger/railz/application_spawner.rb, line 151 151: def spawn_application! 152: a, b = UNIXSocket.pair 153: pid = safe_fork('application', true) do 154: begin 155: a.close 156: 157: file_descriptors_to_leave_open = [0, 1, 2, b.fileno] 158: NativeSupport.close_all_file_descriptors(file_descriptors_to_leave_open) 159: close_all_io_objects_for_fds(file_descriptors_to_leave_open) 160: 161: channel = MessageChannel.new(b) 162: success = report_app_init_status(channel) do 163: ENV['RAILS_ENV'] = @environment 164: ENV['RAILS_RELATIVE_URL_ROOT'] = @base_uri 165: Dir.chdir(@app_root) 166: if @encoded_environment_variables 167: set_passed_environment_variables 168: end 169: if @lower_privilege 170: lower_privilege('config/environment.rb', @lowest_user) 171: end 172: 173: require File.expand_path('config/environment') 174: require 'dispatcher' 175: end 176: if success 177: start_request_handler(channel, false) 178: end 179: rescue SignalException => e 180: if e.message != AbstractRequestHandler::HARD_TERMINATION_SIGNAL && 181: e.message != AbstractRequestHandler::SOFT_TERMINATION_SIGNAL 182: raise 183: end 184: end 185: end 186: b.close 187: Process.waitpid(pid) rescue nil 188: 189: channel = MessageChannel.new(a) 190: unmarshal_and_raise_errors(channel, @print_exceptions) 191: 192: # No exception was raised, so spawning succeeded. 193: pid, socket_name, socket_type = channel.read 194: if pid.nil? 195: raise IOError, "Connection closed" 196: end 197: owner_pipe = channel.recv_io 198: return Application.new(@app_root, pid, socket_name, 199: socket_type, owner_pipe) 200: end
Overrided from AbstractServer#start.
May raise these additional exceptions:
# File lib/phusion_passenger/railz/application_spawner.rb, line 208 208: def start 209: super 210: begin 211: unmarshal_and_raise_errors(server, @print_exceptions) 212: rescue IOError, SystemCallError, SocketError => e 213: stop 214: raise Error, "The application spawner server exited unexpectedly: #{e}" 215: rescue 216: stop 217: raise 218: end 219: end