0
@@ -34,15 +34,15 @@ class FrameworkSpawner < AbstractServer
0
# - <tt>:version</tt>: The Ruby on Rails version to use. It is not checked whether
0
- #
this version is actually installed.
0
+ #
this version is actually installed.
0
# - <tt>:vendor</tt>: The directory to the vendor Rails framework to use. This is
0
- #
usually something like "/webapps/foo/vendor/rails".
0
+ #
usually something like "/webapps/foo/vendor/rails".
0
- # It is not allowed to specify both
<tt>version</tt> and <tt>vendor</tt>.
0
+ # It is not allowed to specify both
+version+ and +vendor+.
0
# Note that the specified Rails framework will be loaded during the entire life time
0
# of the FrameworkSpawner server. If you wish to reload the Rails framework's code,
0
- # then restart the server by calling
stop() and start().
0
+ # then restart the server by calling
AbstractServer#stop and AbstractServer#start.
0
def initialize(options = {})
0
if !options.respond_to?(:'[]')
0
raise ArgumentError, "The 'options' argument not seem to be an options hash"
0
@@ -60,13 +60,34 @@ class FrameworkSpawner < AbstractServer
0
define_message_handler(:reload, :handle_reload)
0
+ # Overrided from AbstractServer#start.
0
+ # This method raises InitializationError if the given Ruby on Rails framework
0
+ # could not be loaded.
0
+ status = server.read[0]
0
+ if status == 'exception'
0
+ child_exception = unmarshal_exception(server.read_scalar)
0
+ message = "Could not load Ruby on Rails framework version #{@version}: " <<
0
+ "#{child_exception.class} (#{child_exception.message})"
0
+ message = "Could not load Ruby on Rails framework at '#{@vendor}': " <<
0
+ "#{child_exception.class} (#{child_exception.message})"
0
+ raise InitializationError.new(message, child_exception)
0
# Spawn a RoR application using the Ruby on Rails framework
0
# version associated with this FrameworkSpawner.
0
# When successful, an Application object will be returned, which represents
0
# the spawned RoR application.
0
- # See ApplicationSpawner.new() for an explanation for the _lower_privilege_
0
- # and _lowest_user_ parameters.
0
+ # See ApplicationSpawner.new for an explanation for the +lower_privilege+
0
+ # and +lowest_user+ parameters.
0
# FrameworkSpawner will internally use ApplicationSpawner, and cache ApplicationSpawner
0
# objects for a while. As a result, spawning an instance of a RoR application for the
0
@@ -78,25 +99,31 @@ class FrameworkSpawner < AbstractServer
0
# - Restart this FrameworkSpawner by calling stop(), then start().
0
# - Reload the application by calling reload().
0
- # If the FrameworkSpawner server hasn't already been started, a ServerNotStarted
0
- # If the RoR application failed to start (which may be a problem in the application,
0
- # or a problem in the Ruby on Rails framework), then a SpawnError
0
- # will be raised. The application's exception message will be printed to standard
0
+ # - AbstractServer::ServerNotStarted: The FrameworkSpawner server hasn't already been started.
0
+ # - ArgumentError: +app_root+ doesn't appear to be a valid Ruby on Rails application root.
0
+ # - InitializationError: The application raised an exception or called exit() during startup.
0
+ # - SpawnError: Something went wrong while spawning the application instance.
0
+ # The application instance's exception message will be printed to standard error.
0
def spawn_application(app_root, lower_privilege = true, lowest_user = "nobody")
0
app_root = normalize_path(app_root)
0
assert_valid_app_root(app_root)
0
server.write("spawn_application", app_root, lower_privilege, lowest_user)
0
- pid, listen_socket_name, using_abstract_namespace = server.read
0
- owner_pipe = server.recv_io
0
- return Application.new(app_root, pid, listen_socket_name,
0
- using_abstract_namespace == "true", owner_pipe)
0
+ raise IOError, "Connection closed"
0
+ elsif result[0] == 'exception'
0
+ raise unmarshal_exception(server.read_scalar)
0
+ pid, listen_socket_name, using_abstract_namespace = server.read
0
+ owner_pipe = server.recv_io
0
+ return Application.new(app_root, pid, listen_socket_name,
0
+ using_abstract_namespace == "true", owner_pipe)
0
rescue SystemCallError, IOError, SocketError
0
- raise SpawnError, "Unable to spawn the application: " <<
0
- "either the Ruby on Rails framework failed to load, " <<
0
- "or the application died unexpectedly during initialization."
0
+ # TODO: consider restarting the corresponding framework spawner
0
+ raise SpawnError, "The framework spawner server exited unexpectedly"
0
@@ -104,7 +131,7 @@ class FrameworkSpawner < AbstractServer
0
# If nil is specified as application root, then all cached application
0
# instances will be removed, no matter the application root.
0
+ #
<b>Long description:</b>0
# Application code might be cached in memory by a FrameworkSpawner. But
0
# once it a while, it will be necessary to reload the code for an
0
# application, such as after deploying a new version of the application.
0
@@ -120,7 +147,7 @@ class FrameworkSpawner < AbstractServer
0
server.write("reload", normalize_path(app_root))
0
rescue SystemCallError, IOError, SocketError
0
- raise IOError, "Cannot send reload command to the framework spawner server
."
0
+ raise IOError, "Cannot send reload command to the framework spawner server
"
0
@@ -136,7 +163,6 @@ protected
0
def initialize_server # :nodoc:
0
$0 = "Passenger FrameworkSpawner: #{@version || @vendor}"
0
@spawners_lock = Mutex.new
0
@spawners_cond = ConditionVariable.new
0
@@ -147,6 +173,14 @@ protected
0
print_exception(self.class.to_s, e)
0
+ rescue StandardError, ScriptError, NoMemoryError => e
0
+ client.write('exception')
0
+ client.write_scalar(marshal_exception(e))
0
+ client.write('success')
0
@@ -194,12 +228,25 @@ private
0
@spawners_lock.synchronize do
0
spawner = @spawners[app_root]
0
- spawner = ApplicationSpawner.new(app_root, lower_privilege, lowest_user)
0
+ spawner = ApplicationSpawner.new(app_root, lower_privilege, lowest_user)
0
+ rescue ArgumentError, InitializationError => e
0
+ client.write('exception')
0
+ client.write_scalar(marshal_exception(e))
0
@spawners[app_root] = spawner
0
spawner.time = Time.now
0
- app = spawner.spawn_application
0
+ app = spawner.spawn_application
0
+ rescue SpawnError => e
0
+ client.write('exception')
0
+ client.write_scalar(marshal_exception(e))
0
+ client.write('success')
0
client.write(app.pid, app.listen_socket_name, app.using_abstract_namespace?)
0
client.send_io(app.owner_pipe)
Comments
No one has commented yet.