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.
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.
# 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
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.
# 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 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.
# 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
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.
# 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
# File lib/phusion_passenger/railz/framework_spawner.rb, line 322 322: def handle_reload(app_root = nil) 323: @spawners.synchronize do 324: if app_root 325: @spawners.delete(app_root) 326: else 327: @spawners.clear 328: end 329: end 330: end
# File lib/phusion_passenger/railz/framework_spawner.rb, line 279 279: def handle_spawn_application(*options) 280: options = sanitize_spawn_options(Hash[*options]) 281: 282: app = nil 283: app_root = options["app_root"] 284: @spawners.synchronize do 285: begin 286: spawner = @spawners.lookup_or_add(app_root) do 287: spawner = ApplicationSpawner.new(app_root, options) 288: if options["app_spawner_timeout"] && options["app_spawner_timeout"] != 1 289: spawner.max_idle_time = options["app_spawner_timeout"] 290: end 291: spawner.start 292: spawner 293: end 294: rescue InvalidPath, AppInitError, ApplicationSpawner::Error => e 295: client.write('exception') 296: client.write_scalar(marshal_exception(e)) 297: if e.respond_to?(:child_exception) && e.child_exception.is_a?(LoadError) 298: # A source file failed to load, maybe because of a 299: # missing gem. If that's the case then the sysadmin 300: # will install probably the gem. So we clear RubyGems's 301: # cache so that it can detect new gems. 302: Gem.clear_paths 303: end 304: return 305: end 306: begin 307: app = spawner.spawn_application 308: rescue ApplicationSpawner::Error => e 309: spawner.stop 310: @spawners.delete(app_root) 311: client.write('exception') 312: client.write_scalar(marshal_exception(e)) 313: return 314: end 315: end 316: client.write('success') 317: client.write(app.pid, app.listen_socket_name, app.listen_socket_type) 318: client.send_io(app.owner_pipe) 319: app.close 320: end
# File lib/phusion_passenger/railz/framework_spawner.rb, line 244 244: def preload_rails 245: Object.const_set(:RAILS_ROOT, ".") 246: if @version 247: gem 'rails', "=#{@version}" 248: require 'initializer' 249: else 250: $LOAD_PATH.unshift("#{@vendor}/railties/builtin/rails_info") 251: Dir["#{@vendor}/*"].each do |entry| 252: next unless File.directory?(entry) 253: $LOAD_PATH.unshift("#{entry}/lib") 254: end 255: require "#{@vendor}/railties/lib/initializer" 256: end 257: require 'active_support' 258: require 'active_record' 259: require 'action_controller' 260: require 'action_view' 261: require 'action_pack' 262: require 'action_mailer' 263: require 'dispatcher' 264: begin 265: if ::Rails::VERSION::MAJOR >= 2 266: require 'active_resource' 267: else 268: require 'action_web_service' 269: end 270: require 'ruby_version_check' 271: require 'active_support/whiny_nil' 272: rescue NameError 273: # Rails < 1.1 274: require 'action_web_service' 275: end 276: Object.send(:remove_const, :RAILS_ROOT) 277: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.