We got nominated! Help us out and vote for GitHub as Best Bootstrapped Startup of 2008. (You can vote once a day.) [ hide ]

public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
passenger / lib / passenger / framework_spawner.rb
bd6e3b45 » Hongli Lai (Phusion) 2008-04-03 Insert GPL headers to sourc... 1 # Phusion Passenger - http://www.modrails.com/
2 # Copyright (C) 2008 Phusion
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; version 2 of the License.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 17 require 'rubygems'
18 require 'socket'
19 require 'pathname'
9d714c0d » Hongli Lai (Phusion) 2008-03-01 Rename 'mod_rails' director... 20 require 'passenger/abstract_server'
21 require 'passenger/application_spawner'
22 require 'passenger/utils'
16201608 » Hongli Lai (Phusion) 2008-03-01 Rename the 'ModRails' names... 23 module Passenger
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 24
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 25 # Raised when FrameworkSpawner or SpawnManager was unable to load a version of
a7d4be71 » Hongli Lai (Phusion) 2008-03-07 Add HTML ERB templates for ... 26 # the Ruby on Rails framework. The +child_exception+ attribute is guaranteed
27 # non-nil.
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 28 class FrameworkInitError < InitializationError
a7d4be71 » Hongli Lai (Phusion) 2008-03-07 Add HTML ERB templates for ... 29 attr_reader :vendor
30 attr_reader :version
31
32 def initialize(message, child_exception, options)
33 super(message, child_exception)
34 if options[:vendor]
35 @vendor = options[:vendor]
36 else
37 @version = options[:version]
38 end
39 end
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 40 end
41
2c9448a9 » Hongli Lai (Phusion) 2008-03-02 Improve documentation 42 # This class is capable of spawning Ruby on Rails application instances
43 # quickly. This is done by preloading the Ruby on Rails framework into memory,
44 # before spawning the application instances.
45 #
46 # A single FrameworkSpawner instance can only hold a single Ruby on Rails
47 # framework version. So be careful when using FrameworkSpawner: the applications
48 # that you spawn through it must require the same RoR version. To handle multiple
49 # RoR versions, use multiple FrameworkSpawner instances.
50 #
51 # FrameworkSpawner uses ApplicationSpawner internally.
52 #
53 # *Note*: FrameworkSpawner may only be started asynchronously with AbstractServer#start.
54 # Starting it synchronously with AbstractServer#start_synchronously has not been tested.
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 55 class FrameworkSpawner < AbstractServer
56 APP_SPAWNER_MAX_IDLE_TIME = 120
82065691 » Hongli Lai (Phusion) 2008-03-31 Fix some Rails compatibilit... 57 APP_SPAWNER_CLEAN_INTERVAL = APP_SPAWNER_MAX_IDLE_TIME + 5
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 58
59 include Utils
412648e0 » Hongli Lai (Phusion) 2008-01-25 Finish the spawn manager. 60
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 61 # This exception means that the FrameworkSpawner server process exited unexpectedly.
62 class Error < AbstractServer::ServerError
63 end
64
16201608 » Hongli Lai (Phusion) 2008-03-01 Rename the 'ModRails' names... 65 # An attribute, used internally. This should not be used outside Passenger.
412648e0 » Hongli Lai (Phusion) 2008-01-25 Finish the spawn manager. 66 attr_accessor :time
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 67
68 # Creates a new instance of FrameworkSpawner.
69 #
c296409f » Hongli Lai (Phusion) 2008-02-27 Move Rails application vers... 70 # Valid options:
71 # - <tt>:version</tt>: The Ruby on Rails version to use. It is not checked whether
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 72 # this version is actually installed.
c296409f » Hongli Lai (Phusion) 2008-02-27 Move Rails application vers... 73 # - <tt>:vendor</tt>: The directory to the vendor Rails framework to use. This is
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 74 # usually something like "/webapps/foo/vendor/rails".
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 75 #
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 76 # It is not allowed to specify both +version+ and +vendor+.
c296409f » Hongli Lai (Phusion) 2008-02-27 Move Rails application vers... 77 #
78 # Note that the specified Rails framework will be loaded during the entire life time
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 79 # of the FrameworkSpawner server. If you wish to reload the Rails framework's code,
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 80 # then restart the server by calling AbstractServer#stop and AbstractServer#start.
c296409f » Hongli Lai (Phusion) 2008-02-27 Move Rails application vers... 81 def initialize(options = {})
16201608 » Hongli Lai (Phusion) 2008-03-01 Rename the 'ModRails' names... 82 if !options.respond_to?(:'[]')
83 raise ArgumentError, "The 'options' argument not seem to be an options hash"
84 end
c296409f » Hongli Lai (Phusion) 2008-02-27 Move Rails application vers... 85 @version = options[:version]
86 @vendor = options[:vendor]
16201608 » Hongli Lai (Phusion) 2008-03-01 Rename the 'ModRails' names... 87 if !@version && !@vendor
88 raise ArgumentError, "Either the 'version' or the 'vendor' option must specified"
89 elsif @version && @vendor
90 raise ArgumentError, "It is not allowed to specify both the 'version' and the 'vendor' options"
91 end
92
93 super()
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 94 define_message_handler(:spawn_application, :handle_spawn_application)
95 define_message_handler(:reload, :handle_reload)
96 end
97
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 98 # Overrided from AbstractServer#start.
99 #
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 100 # May raise these additional exceptions:
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 101 # - FrameworkInitError: The specified Ruby on Rails framework could not be loaded.
102 # - FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 103 def start
104 super
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 105 begin
106 status = server.read[0]
107 if status == 'exception'
108 child_exception = unmarshal_exception(server.read_scalar)
109 stop
110 if @version
111 message = "Could not load Ruby on Rails framework version #{@version}: " <<
112 "#{child_exception.class} (#{child_exception.message})"
113 else
114 message = "Could not load Ruby on Rails framework at '#{@vendor}': " <<
115 "#{child_exception.class} (#{child_exception.message})"
116 end
a7d4be71 » Hongli Lai (Phusion) 2008-03-07 Add HTML ERB templates for ... 117 options = { :vendor => @vendor, :version => @version }
118 raise FrameworkInitError.new(message, child_exception, options)
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 119 end
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 120 rescue IOError, SystemCallError, SocketError
121 stop
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 122 raise Error, "The framework spawner server exited unexpectedly"
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 123 end
124 end
125
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 126 # Spawn a RoR application using the Ruby on Rails framework
127 # version associated with this FrameworkSpawner.
128 # When successful, an Application object will be returned, which represents
129 # the spawned RoR application.
130 #
fb13dec0 » Hongli Lai (Phusion) 2008-05-07 Turn RailsEnv into a per-vi... 131 # See ApplicationSpawner.new for an explanation of the +lower_privilege+,
132 # +lowest_user+ and +environment+ parameters.
b2d4cc2f » Hongli Lai (Phusion) 2008-02-23 Implement user switching su... 133 #
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 134 # FrameworkSpawner will internally cache the code of applications, in order to
135 # speed up future spawning attempts. This implies that, if you've changed
136 # the application's code, you must do one of these things:
137 # - Restart this FrameworkSpawner by calling AbstractServer#stop, then AbstractServer#start.
138 # - Reload the application by calling reload with the correct app_root argument.
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 139 #
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 140 # Raises:
141 # - AbstractServer::ServerNotStarted: The FrameworkSpawner server hasn't already been started.
142 # - ArgumentError: +app_root+ doesn't appear to be a valid Ruby on Rails application root.
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 143 # - AppInitError: The application raised an exception or called exit() during startup.
144 # - ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
145 # - FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.
fb13dec0 » Hongli Lai (Phusion) 2008-05-07 Turn RailsEnv into a per-vi... 146 def spawn_application(app_root, lower_privilege = true, lowest_user = "nobody", environment = "production")
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 147 app_root = normalize_path(app_root)
148 assert_valid_app_root(app_root)
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 149 exception_to_propagate = nil
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 150 begin
fb13dec0 » Hongli Lai (Phusion) 2008-05-07 Turn RailsEnv into a per-vi... 151 server.write("spawn_application", app_root, lower_privilege, lowest_user, environment)
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 152 result = server.read
153 if result.nil?
154 raise IOError, "Connection closed"
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 155 end
156 if result[0] == 'exception'
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 157 raise unmarshal_exception(server.read_scalar)
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 158 else
159 pid, listen_socket_name, using_abstract_namespace = server.read
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 160 if pid.nil?
161 raise IOError, "Connection closed"
162 end
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 163 owner_pipe = server.recv_io
164 return Application.new(app_root, pid, listen_socket_name,
165 using_abstract_namespace == "true", owner_pipe)
166 end
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 167 rescue SystemCallError, IOError, SocketError => e
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 168 raise Error, "The framework spawner server exited unexpectedly"
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 169 end
170 end
171
763b9371 » Hongli Lai (Phusion) 2008-02-26 *Really* implement restarti... 172 # Remove the cached application instances at the given application root.
173 # If nil is specified as application root, then all cached application
174 # instances will be removed, no matter the application root.
175 #
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 176 # <b>Long description:</b>
763b9371 » Hongli Lai (Phusion) 2008-02-26 *Really* implement restarti... 177 # Application code might be cached in memory by a FrameworkSpawner. But
178 # once it a while, it will be necessary to reload the code for an
179 # application, such as after deploying a new version of the application.
180 # This method makes sure that any cached application code is removed, so
181 # that the next time an application instance is spawned, the application
182 # code will be freshly loaded into memory.
183 #
98c09711 » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 184 # Raises:
185 # - ArgumentError: +app_root+ doesn't appear to be a valid Ruby on Rails
186 # application root.
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 187 # - FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.
412648e0 » Hongli Lai (Phusion) 2008-01-25 Finish the spawn manager. 188 def reload(app_root = nil)
189 if app_root.nil?
ccd01b56 » Hongli Lai (Phusion) 2008-02-23 Refactor AbstractServer and... 190 server.write("reload")
412648e0 » Hongli Lai (Phusion) 2008-01-25 Finish the spawn manager. 191 else
ccd01b56 » Hongli Lai (Phusion) 2008-02-23 Refactor AbstractServer and... 192 server.write("reload", normalize_path(app_root))
412648e0 » Hongli Lai (Phusion) 2008-01-25 Finish the spawn manager. 193 end
763b9371 » Hongli Lai (Phusion) 2008-02-26 *Really* implement restarti... 194 rescue SystemCallError, IOError, SocketError
cec5c76b » Hongli Lai (Phusion) 2008-03-07 Reorganize exception hierar... 195 raise Error, "The framework spawner server exited unexpectedly"
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 196 end
197
198 protected
199 # Overrided method.
d73f7e27 » Hongli Lai (Phusion) 2008-02-22 Improve documentation and d... 200 def before_fork # :nodoc:
b28fbb8f » Hongli Lai (Phusion) 2008-03-17 Synchronize with recent EMM... 201 if GC.copy_on_write_friendly?
202 # Garbage collect now so that the child process doesn't have to
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 203 # do that (to prevent making pages dirty).
204 GC.start
205 end
206 end
207
208 # Overrided method.
d73f7e27 » Hongli Lai (Phusion) 2008-02-22 Improve documentation and d... 209 def initialize_server # :nodoc:
1e21c0e7 » Hongli Lai (Phusion) 2008-02-29 Aggressively close file des... 210 $0 = "Passenger FrameworkSpawner: #{@version || @vendor}"
be0f3b4e » Hongli Lai (Phusion) 2008-01-25 Initial import. 211 @spawners = {}
212 @spawners_lock = Mutex.new
213 @spawners_cond = ConditionVariable.new
214 @spawners_cleaner = Thread.new do
215 begin
216 spawners_cleaner_main_loop
217 rescue Exception => e
218 print_exception(self.class.to_s, e)
219 end
220 end
d21001ab » Hongli Lai (Phusion) 2008-03-03 Improve error handling in A... 221 begin
222 preload_rails
223 rescue StandardError, ScriptError, NoMemoryError => e
224 client.write('exception')
225 client.write_scalar(marshal_exception(e))
226 return
227 end
228 client.write(&#