This class is capable of spawning Ruby on Rails application instances. Spawning a Ruby on Rails application is usually slow. But SpawnManager will preload and cache Ruby on Rails frameworks, as well as application code, so subsequent spawns will be very fast.
Internally, SpawnManager uses FrameworkSpawner to preload and cache Ruby on Rails frameworks. FrameworkSpawner, in turn, uses ApplicationSpawner to preload and cache application code.
Note: SpawnManager may only be started synchronously with AbstractServer#start_synchronously. Starting asynchronously has not been tested. Don‘t forget to call cleanup after the server‘s main loop has finished.
DEFAULT_INPUT_FD | = | 3 |
FRAMEWORK_SPAWNER_MAX_IDLE_TIME | = | 30 * 60 |
APP_SPAWNER_MAX_IDLE_TIME | = | FrameworkSpawner::APP_SPAWNER_MAX_IDLE_TIME |
SPAWNER_CLEAN_INTERVAL | = | [FRAMEWORK_SPAWNER_MAX_IDLE_TIME, APP_SPAWNER_MAX_IDLE_TIME].min + 5 |
[ show source ]
# File lib/passenger/spawn_manager.rb, line 48 48: def initialize 49: super() 50: @spawners = {} 51: @lock = Mutex.new 52: @cond = ConditionVariable.new 53: @cleaner_thread = Thread.new do 54: cleaner_thread_main 55: end 56: define_message_handler(:spawn_application, :handle_spawn_application) 57: define_message_handler(:reload, :handle_reload) 58: define_signal_handler('SIGHUP', :reload) 59: end
Cleanup resources. Should be called when this SpawnManager is no longer needed.
[ show source ]
# File lib/passenger/spawn_manager.rb, line 165 165: def cleanup 166: @lock.synchronize do 167: @cond.signal 168: end 169: @cleaner_thread.join 170: @lock.synchronize do 171: @spawners.each_value do |spawner| 172: spawner.stop 173: end 174: @spawners.clear 175: end 176: 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. 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 AbstractServer::SpawnError if something went wrong.
[ show source ]
# File lib/passenger/spawn_manager.rb, line 138 138: def reload(app_root = nil) 139: if app_root 140: begin 141: app_root = normalize_path(app_root) 142: rescue ArgumentError 143: end 144: end 145: @lock.synchronize do 146: if app_root 147: # Delete associated ApplicationSpawner. 148: key = "app:#{app_root}" 149: spawner = @spawners[key] 150: if spawner 151: spawner.stop 152: @spawners.delete(key) 153: end 154: end 155: @spawners.each_value do |spawner| 156: # Reload FrameworkSpawners. 157: if spawner.respond_to?(:reload) 158: spawner.reload(app_root) 159: end 160: end 161: end 162: end
Spawn a RoR application When successful, an Application object will be returned, which represents the spawned RoR application.
See ApplicationSpawner.new for an explanation of the lower_privilege and lowest_user parameters.
SpawnManager 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 SpawnManager by calling AbstractServer#stop, then AbstractServer#start.
- Reload the application by calling reload with the correct app_root argument.
Raises:
- ArgumentError: app_root doesn‘t appear to be a valid Ruby on Rails application root.
- VersionNotFound: The Ruby on Rails framework version that the given application requires is not installed.
- AbstractServer::ServerError: One of the server processes exited unexpectedly.
- FrameworkInitError: The Ruby on Rails framework that the application requires could not be loaded.
- AppInitError: The application raised an exception or called exit() during startup.
[ show source ]
# File lib/passenger/spawn_manager.rb, line 80 80: def spawn_application(app_root, lower_privilege = true, lowest_user = "nobody") 81: framework_version = Application.detect_framework_version(app_root) 82: if framework_version == :vendor 83: vendor_path = normalize_path("#{app_root}/vendor/rails") 84: key = "vendor:#{vendor_path}" 85: create_spawner = proc do 86: FrameworkSpawner.new(:vendor => vendor_path) 87: end 88: elsif framework_version.nil? 89: app_root = normalize_path(app_root) 90: key = "app:#{app_root}" 91: create_spawner = proc do 92: ApplicationSpawner.new(app_root, lower_privilege, lowest_user) 93: end 94: else 95: key = "version:#{framework_version}" 96: create_spawner = proc do 97: FrameworkSpawner.new(:version => framework_version) 98: end 99: end 100: 101: spawner = nil 102: @lock.synchronize do 103: spawner = @spawners[key] 104: if !spawner 105: spawner = create_spawner.call 106: spawner.start 107: @spawners[key] = spawner 108: end 109: spawner.time = Time.now 110: begin 111: if spawner.is_a?(FrameworkSpawner) 112: return spawner.spawn_application(app_root, lower_privilege, 113: lowest_user) 114: else 115: return spawner.spawn_application 116: end 117: rescue AbstractServer::ServerError 118: spawner.stop 119: @spawners.delete(key) 120: raise 121: end 122: end 123: end