Included Modules

Class Index [+]

Quicksearch

PhusionPassenger::Railz::FrameworkSpawner

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.

Public Class Methods

new(options = {}) click to toggle source

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

Public Instance Methods

reload(app_root = nil) click to toggle source

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_application(app_root, options = {}) click to toggle source

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:

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
start() click to toggle source

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

Private Instance Methods

handle_reload(app_root = nil) click to toggle source
     # 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
handle_spawn_application(*options) click to toggle source
     # 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
preload_rails() click to toggle source
     # 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.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.