Class: PhusionPassenger::Railz::ApplicationSpawner
- Inherits:
-
AbstractServer
- Object
- AbstractServer
- PhusionPassenger::Railz::ApplicationSpawner
- Includes:
- Utils
- Defined in:
- lib/phusion_passenger/railz/application_spawner.rb
Overview
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.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- ROOT_UID =
The user ID of the root user.
0
- ROOT_GID =
The group ID of the root user.
0
Constants inherited from AbstractServer
AbstractServer::SERVER_TERMINATION_SIGNAL
Instance Attribute Summary collapse
-
#app_root ⇒ Object
readonly
The application root of this spawner.
Attributes inherited from AbstractServer
#last_activity_time, #max_idle_time, #next_cleaning_time
Instance Method Summary collapse
-
#initialize(app_root, options = {}) ⇒ ApplicationSpawner
constructor
app_root
is the root directory of this application, i.e. -
#spawn_application ⇒ Object
Spawn an instance of the RoR application.
-
#spawn_application! ⇒ Object
Spawn an instance of the RoR application.
-
#start ⇒ Object
Overrided from AbstractServer#start.
Methods inherited from AbstractServer
#server_pid, #start_synchronously, #started?, #stop
Constructor Details
#initialize(app_root, options = {}) ⇒ ApplicationSpawner
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:
-
lower_privilege
andlowest_user
: Iflower_privilege
is true, then ApplicationSpawner will attempt to switch to the user who owns the application’sconfig/environment.rb
, and to the default group of that user.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). Iflowest_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. -
environment
: Allows one to specify the RAILS_ENV environment to use. -
environment_variables
: Environment variables which should be passed to the spawned application. This is NULL-seperated string of key-value pairs, encoded in base64. The last byte in the unencoded data must be a NULL. -
base_uri
: The base URI on which this application is deployed. It equals “/” string if the application is deployed on the root URI. It must not equal the empty string. -
print_exceptions
: Whether exceptions that have occurred during application initialization should be printed to STDERR. The default is true.
All other options will be passed on to RequestHandler.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/phusion_passenger/railz/application_spawner.rb', line 102 def initialize(app_root, = {}) super() @app_root = app_root @canonicalized_app_root = canonicalize_path(app_root) @options = () @lower_privilege = @options["lower_privilege"] @lowest_user = @options["lowest_user"] @environment = @options["environment"] @encoded_environment_variables = @options["environment_variables"] @base_uri = @options["base_uri"] if @options["base_uri"] && @options["base_uri"] != "/" @print_exceptions = @options["print_exceptions"] self.max_idle_time = DEFAULT_APP_SPAWNER_MAX_IDLE_TIME assert_valid_app_root(@app_root) (:spawn_application, :handle_spawn_application) end |
Instance Attribute Details
#app_root ⇒ Object (readonly)
The application root of this spawner.
64 65 66 |
# File 'lib/phusion_passenger/railz/application_spawner.rb', line 64 def app_root @app_root end |
Instance Method Details
#spawn_application ⇒ Object
Spawn an instance of the RoR application. When successful, an Application object will be returned, which represents the spawned RoR application.
Raises:
-
AbstractServer::ServerNotStarted: The ApplicationSpawner server hasn’t already been started.
-
ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/phusion_passenger/railz/application_spawner.rb', line 124 def spawn_application server.write("spawn_application") pid, socket_name, socket_type = server.read if pid.nil? raise IOError, "Connection closed" end owner_pipe = server.recv_io return Application.new(@app_root, pid, socket_name, socket_type, owner_pipe) rescue SystemCallError, IOError, SocketError => e raise Error, "The application spawner server exited unexpectedly: #{e}" end |
#spawn_application! ⇒ Object
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:
-
AppInitError: The Ruby on Rails application raised an exception or called exit() during startup.
-
SystemCallError, IOError, SocketError: Something went wrong.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/phusion_passenger/railz/application_spawner.rb', line 151 def spawn_application! a, b = UNIXSocket.pair pid = safe_fork('application', true) do begin 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) success = report_app_init_status(channel) do ENV['RAILS_ENV'] = @environment ENV['RAILS_RELATIVE_URL_ROOT'] = @base_uri Dir.chdir(@app_root) if @encoded_environment_variables set_passed_environment_variables end if @lower_privilege lower_privilege('config/environment.rb', @lowest_user) end # Make sure RubyGems uses any new environment variable values # that have been set now (e.g. $HOME, $GEM_HOME, etc) and that # it is able to detect newly installed gems. Gem.clear_paths require File.('config/environment') require 'dispatcher' end if success start_request_handler(channel, false) end rescue SignalException => e if e. != AbstractRequestHandler::HARD_TERMINATION_SIGNAL && e. != AbstractRequestHandler::SOFT_TERMINATION_SIGNAL raise end end end b.close Process.waitpid(pid) rescue nil channel = MessageChannel.new(a) unmarshal_and_raise_errors(channel, @print_exceptions) # No exception was raised, so spawning succeeded. pid, socket_name, socket_type = channel.read if pid.nil? raise IOError, "Connection closed" end owner_pipe = channel.recv_io return Application.new(@app_root, pid, socket_name, socket_type, owner_pipe) end |
#start ⇒ Object
Overrided from AbstractServer#start.
May raise these additional exceptions:
-
AppInitError: The Ruby on Rails application raised an exception or called exit() during startup.
-
ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/phusion_passenger/railz/application_spawner.rb', line 212 def start super begin unmarshal_and_raise_errors(server, @print_exceptions) rescue IOError, SystemCallError, SocketError => e stop raise Error, "The application spawner server exited unexpectedly: #{e}" rescue stop raise end end |