Class PhusionPassenger::Railz::FrameworkSpawner |
In: | lib/phusion_passenger/railz/framework_spawner.rb
Parent: | AbstractServer

This class is capable of spawning Ruby on Rails application instances quickly. This is done by preloading the Ruby on Rails framework into memory, before spawning the application instances.

A single FrameworkSpawner instance can only hold a single Ruby on Rails framework version. So be careful when using FrameworkSpawner: the applications that you spawn through it must require the same RoR version. To handle multiple RoR versions, use multiple FrameworkSpawner instances.

FrameworkSpawner uses ApplicationSpawner internally.

Note: FrameworkSpawner may only be started asynchronously with AbstractServer#start. Starting it synchronously with AbstractServer#start_synchronously has not been tested.

Methods

- new
- reload
- spawn_application
- start

Included Modules

- Utils

Classes and Modules
Class PhusionPassenger::Railz::FrameworkSpawner::Error
Public Class methods
new(options = {})

Creates a new instance of FrameworkSpawner.

Valid options are:

- `:version`: The Ruby on Rails version to use. It is not checked whether this version is actually installed.
- `:vendor`: The directory to the vendor Rails framework to use. This is usually something like "/webapps/foo/vendor/rails".
- `:print_framework_loading_exceptions`: Whether exceptions that have occurred while loading the Ruby on Rails framework should be printed to STDERR. The default is true.

It is not allowed to specify both `version` and `vendor`.

All other options will be passed on to ApplicationSpawner and RequestHandler.

Note that the specified Rails framework will be loaded during the entire life time of the FrameworkSpawner server. If you wish to reload the Rails framework‘s code, then restart the server by calling AbstractServer#stop and AbstractServer#start.

[ show source ]

        # File lib/phusion_passenger/railz/framework_spawner.rb, line 72
    72:         def initialize(options = {})
    73:                 if !options.respond_to?('[]''[]')
    74:                         raise ArgumentError, "The 'options' argument not seem to be an options hash"
    75:                 end
    76:                 @version = options[:version]
    77:                 @vendor  = options[:vendor]
    78:                 if options.has_key?(:print_framework_loading_exceptions)
    79:                         @print_framework_loading_exceptions = options[:print_framework_loading_exceptions]
    80:                 else
    81:                         @print_framework_loading_exceptions = true
    82:                 end
    83:                 if !@version && !@vendor
    84:                         raise ArgumentError, "Either the 'version' or the 'vendor' option must specified"
    85:                 elsif @version && @vendor
    86:                         raise ArgumentError, "It is not allowed to specify both the 'version' and the 'vendor' options"
    87:                 end
    88:
    89:                 super()
    90:                 self.max_idle_time = DEFAULT_FRAMEWORK_SPAWNER_MAX_IDLE_TIME
    91:                 define_message_handler(:spawn_application, :handle_spawn_application)
    92:                 define_message_handler(:reload, :handle_reload)
    93:         end

Public Instance methods
reload(app_root = nil)

Remove the cached application instances at the given application root. If nil is specified as application root, then all cached application instances will be removed, no matter the application root.

Long description: Application code might be cached in memory by a FrameworkSpawner. But once it a while, it will be necessary to reload the code for an application, such as after deploying a new version of the application. This method makes sure that any cached application code is removed, so that the next time an application instance is spawned, the application code will be freshly loaded into memory.

Raises:

- ArgumentError: `app_root` doesn‘t appear to be a valid Ruby on Rails application root.
- FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.

[ show source ]

         # File lib/phusion_passenger/railz/framework_spawner.rb, line 204
    204:         def reload(app_root = nil)
    205:                 if app_root.nil?
    206:                         server.write("reload")
    207:                 else
    208:                         server.write("reload", app_root)
    209:                 end
    210:         rescue SystemCallError, IOError, SocketError
    211:                 raise Error, "The framework spawner server exited unexpectedly"
    212:         end

spawn_application(app_root, options = {})

Spawn a RoR application using the Ruby on Rails framework version associated with this FrameworkSpawner. When successful, an Application object will be returned, which represents the spawned RoR application.

All options accepted by ApplicationSpawner.new and RequestHandler.new are accepted.

FrameworkSpawner will internally cache the code of applications, in order to speed up future spawning attempts. This implies that, if you‘ve changed the application‘s code, you must do one of these things:

- Restart this FrameworkSpawner by calling AbstractServer#stop, then AbstractServer#start.
- Reload the application by calling reload with the correct app_root argument.

Raises:

- AbstractServer::ServerNotStarted: The FrameworkSpawner server hasn‘t already been started.
- InvalidPath: `app_root` doesn‘t appear to be a valid Ruby on Rails application root.
- AppInitError: The application raised an exception or called exit() during startup.
- ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
- FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.

[ show source ]

         # File lib/phusion_passenger/railz/framework_spawner.rb, line 150
    150:         def spawn_application(app_root, options = {})
    151:                 assert_valid_app_root(app_root)
    152:                 options = sanitize_spawn_options(options)
    153:                 options["app_root"] = app_root
    154:                 # No need for the ApplicationSpawner to print exceptions. All
    155:                 # exceptions raised by the ApplicationSpawner are sent back here,
    156:                 # so we just need to decide here whether we want to print it.
    157:                 print_exceptions = options["print_exceptions"]
    158:                 options["print_exceptions"] = false
    159:
    160:                 begin
    161:                         server.write("spawn_application", *options.to_a.flatten)
    162:                         result = server.read
    163:                         if result.nil?
    164:                                 raise IOError, "Connection closed"
    165:                         end
    166:                         if result[0] == 'exception'
    167:                                 e = unmarshal_exception(server.read_scalar)
    168:                                 if print_exceptions && e.respond_to?(:child_exception) && e.child_exception
    169:                                         print_exception(self.class.to_s, e.child_exception)
    170:                                 elsif print_exceptions
    171:                                         print_exception(self.class.to_s, e)
    172:                                 end
    173:                                 raise e
    174:                         else
    175:                                 pid, listen_socket_name, socket_type = server.read
    176:                                 if pid.nil?
    177:                                         raise IOError, "Connection closed"
    178:                                 end
    179:                                 owner_pipe = server.recv_io
    180:                                 return Application.new(app_root, pid, listen_socket_name,
    181:                                         socket_type, owner_pipe)
    182:                         end
    183:                 rescue SystemCallError, IOError, SocketError => e
    184:                         raise Error, "The framework spawner server exited unexpectedly"
    185:                 end
    186:         end

start()

Overrided from AbstractServer#start.

May raise these additional exceptions:

- FrameworkInitError: An error occurred while loading the specified Ruby on Rails framework.
- FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.

[ show source ]

         # File lib/phusion_passenger/railz/framework_spawner.rb, line 100
    100:         def start
    101:                 super
    102:                 begin
    103:                         result = server.read
    104:                         if result.nil?
    105:                                 raise Error, "The framework spawner server exited unexpectedly."
    106:                         else
    107:                                 status = result[0]
    108:                         end
    109:                         if status == 'exception'
    110:                                 child_exception = unmarshal_exception(server.read_scalar)
    111:                                 stop
    112:                                 if @version
    113:                                         message = "Could not load Ruby on Rails framework version #{@version}: " <<
    114:                                                 "#{child_exception.class} (#{child_exception.message})"
    115:                                 else
    116:                                         message = "Could not load Ruby on Rails framework at '#{@vendor}': " <<
    117:                                                 "#{child_exception.class} (#{child_exception.message})"
    118:                                 end
    119:                                 options = { :vendor => @vendor, :version => @version }
    120:                                 if @print_framework_loading_exceptions
    121:                                         print_exception(self.class.to_s, child_exception)
    122:                                 end
    123:                                 raise FrameworkInitError.new(message, child_exception, options)
    124:                         end
    125:                 rescue IOError, SystemCallError, SocketError
    126:                         stop
    127:                         raise Error, "The framework spawner server exited unexpectedly"
    128:                 end
    129:         end