Class: PhusionPassenger::RequestHandler
- Includes:
- DebugLogging, Utils
- Defined in:
- lib/phusion_passenger/request_handler.rb,
lib/phusion_passenger/request_handler/thread_handler.rb
Defined Under Namespace
Classes: ThreadHandler
Constant Summary collapse
- HARD_TERMINATION_SIGNAL =
Signal which will cause the Rails application to exit immediately.
"SIGTERM"
- SOFT_TERMINATION_SIGNAL =
Signal which will cause the Rails application to exit as soon as it’s done processing a request.
"SIGUSR1"
- BACKLOG_SIZE =
500
- IGNORE =
String constants which exist to relieve Ruby’s garbage collector.
'IGNORE'
- DEFAULT =
:nodoc:
'DEFAULT'
Instance Attribute Summary collapse
-
#concurrency ⇒ Object
readonly
Returns the value of attribute concurrency.
-
#connect_password ⇒ Object
A password with which clients must authenticate.
-
#server_sockets ⇒ Object
readonly
A hash containing all server sockets that this request handler listens on.
-
#soft_termination_linger_time ⇒ Object
If a soft termination signal was received, then the main loop will quit the given amount of seconds after the last time a connection was accepted.
Instance Method Summary collapse
-
#cleanup ⇒ Object
Clean up temporary stuff created by the request handler.
-
#initialize(owner_pipe, options = {}) ⇒ RequestHandler
constructor
Create a new RequestHandler with the given owner pipe.
-
#main_loop ⇒ Object
Enter the request handler’s main loop.
-
#main_loop_running? ⇒ Boolean
Check whether the main loop’s currently running.
-
#soft_shutdown ⇒ Object
Remove this request handler from the application pool so that no new connections will come in.
-
#start_main_loop_thread ⇒ Object
Start the main loop in a new thread.
Methods included from Utils
#connect_to_server, #generate_random_id, #get_socket_address_type, #global_backtrace_report, #home_dir, included, #install_options_as_ivars, #local_socket_address?, mktmpdir, #print_exception, #process_is_alive?, #require_option, #retry_at_most
Methods included from DebugLogging
_log_device, debug, error, included, log_file=, log_level, log_level=, stderr_evaluator=, trace, warn
Constructor Details
#initialize(owner_pipe, options = {}) ⇒ RequestHandler
Create a new RequestHandler with the given owner pipe. owner_pipe
must be the readable part of a pipe IO object.
Additionally, the following options may be given:
-
detach_key
-
connect_password
-
pool_account_username
-
pool_account_password_base64
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/phusion_passenger/request_handler.rb', line 88 def initialize(owner_pipe, = {}) require_option(, "app_group_name") (self, , "app", "app_group_name", "connect_password", "detach_key", "union_station_core", "pool_account_username" ) @force_http_session = ENV["_PASSENGER_FORCE_HTTP_SESSION"] == "true" if @force_http_session @connect_password = nil end @thread_handler = ["thread_handler"] || ThreadHandler @concurrency = 1 if ["pool_account_password_base64"] @pool_account_password = ["pool_account_password_base64"].unpack('m').first end ############# ############# @server_sockets = {} if should_use_unix_sockets? @main_socket_address, @main_socket = create_unix_socket_on_filesystem() else @main_socket_address, @main_socket = create_tcp_socket end @server_sockets[:main] = { :address => @main_socket_address, :socket => @main_socket, :protocol => @force_http_session ? :http_session : :session, :concurrency => @concurrency } @http_socket_address, @http_socket = create_tcp_socket @server_sockets[:http] = { :address => @http_socket_address, :socket => @http_socket, :protocol => :http, :concurrency => 1 } @owner_pipe = owner_pipe @options = @previous_signal_handlers = {} @main_loop_generation = 0 @main_loop_thread_lock = Mutex.new @main_loop_thread_cond = ConditionVariable.new @threads = [] @threads_mutex = Mutex.new @soft_termination_linger_time = 3 @main_loop_running = false ############# end |
Instance Attribute Details
#concurrency ⇒ Object (readonly)
Returns the value of attribute concurrency.
70 71 72 |
# File 'lib/phusion_passenger/request_handler.rb', line 70 def concurrency @concurrency end |
#connect_password ⇒ Object
A password with which clients must authenticate. Default is unauthenticated.
78 79 80 |
# File 'lib/phusion_passenger/request_handler.rb', line 78 def connect_password @connect_password end |
#server_sockets ⇒ Object (readonly)
A hash containing all server sockets that this request handler listens on. The hash is in the form of:
{
name1 => [socket_address1, socket_type1, socket1],
name2 => [socket_address2, socket_type2, socket2],
...
}
name
is a Symbol. socket_addressx
is the address of the socket, socket_typex
is the socket’s type (either ‘unix’ or ‘tcp’) and socketx
is the actual socket IO objec. There’s guaranteed to be at least one server socket, namely one with the name :main
.
68 69 70 |
# File 'lib/phusion_passenger/request_handler.rb', line 68 def server_sockets @server_sockets end |
#soft_termination_linger_time ⇒ Object
If a soft termination signal was received, then the main loop will quit the given amount of seconds after the last time a connection was accepted. Defaults to 3 seconds.
75 76 77 |
# File 'lib/phusion_passenger/request_handler.rb', line 75 def soft_termination_linger_time @soft_termination_linger_time end |
Instance Method Details
#cleanup ⇒ Object
Clean up temporary stuff created by the request handler.
If the main loop was started by #main_loop, then this method may only be called after the main loop has exited.
If the main loop was started by #start_main_loop_thread, then this method may be called at any time, and it will stop the main loop thread.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/phusion_passenger/request_handler.rb', line 155 def cleanup if @main_loop_thread @main_loop_thread_lock.synchronize do @graceful_termination_pipe[1].close rescue nil end @main_loop_thread.join end @server_sockets.each_value do |info| socket = info[:socket] type = get_socket_address_type(info[:address]) socket.close if !socket.closed? if type == :unix filename = info[:address].sub(/^unix:/, '') File.unlink(filename) rescue nil end end @owner_pipe.close rescue nil end |
#main_loop ⇒ Object
Enter the request handler’s main loop.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/phusion_passenger/request_handler.rb', line 183 def main_loop debug("Entering request handler main loop") reset_signal_handlers begin @graceful_termination_pipe = IO.pipe @graceful_termination_pipe[0].close_on_exec! @graceful_termination_pipe[1].close_on_exec! @main_loop_thread_lock.synchronize do @main_loop_generation += 1 @main_loop_running = true @main_loop_thread_cond.broadcast @select_timeout = nil @selectable_sockets = [] @server_sockets.each_value do |value| socket = value[2] @selectable_sockets << socket if socket end @selectable_sockets << @owner_pipe @selectable_sockets << @graceful_termination_pipe[0] end install_useful_signal_handlers start_threads wait_until_termination_requested wait_until_all_threads_are_idle terminate_threads debug("Request handler main loop exited normally") rescue EOFError # Exit main loop. trace(2, "Request handler main loop interrupted by EOFError exception") rescue Interrupt # Exit main loop. trace(2, "Request handler main loop interrupted by Interrupt exception") rescue SignalException => signal trace(2, "Request handler main loop interrupted by SignalException") if signal. != HARD_TERMINATION_SIGNAL && signal. != SOFT_TERMINATION_SIGNAL raise end rescue Exception => e trace(2, "Request handler main loop interrupted by #{e.class} exception") raise ensure debug("Exiting request handler main loop") revert_signal_handlers @main_loop_thread_lock.synchronize do @graceful_termination_pipe[1].close rescue nil @graceful_termination_pipe[0].close rescue nil @selectable_sockets = [] @main_loop_generation += 1 @main_loop_running = false @main_loop_thread_cond.broadcast end end end |
#main_loop_running? ⇒ Boolean
Check whether the main loop’s currently running.
176 177 178 179 180 |
# File 'lib/phusion_passenger/request_handler.rb', line 176 def main_loop_running? @main_loop_thread_lock.synchronize do return @main_loop_running end end |
#soft_shutdown ⇒ Object
Remove this request handler from the application pool so that no new connections will come in. Then make the main loop quit a few seconds after the last time a connection came in. This all is to ensure that no connections come in while we’re shutting down.
May only be called while the main loop is running. May be called from any thread.
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/phusion_passenger/request_handler.rb', line 267 def soft_shutdown @soft_termination_linger_thread ||= Thread.new do debug("Soft termination initiated") if @detach_key && @pool_account_username && @pool_account_password client = MessageClient.new(@pool_account_username, @pool_account_password) begin client.pool_detach_process_by_key(@detach_key) ensure client.close end end wait_until_all_threads_are_idle debug("Soft terminating in #{@soft_termination_linger_time} seconds") sleep @soft_termination_linger_time @graceful_termination_pipe[1].close rescue nil end end |
#start_main_loop_thread ⇒ Object
Start the main loop in a new thread. This thread will be stopped by #cleanup.
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/phusion_passenger/request_handler.rb', line 244 def start_main_loop_thread current_generation = @main_loop_generation @main_loop_thread = Thread.new do begin main_loop rescue Exception => e print_exception(self.class, e) end end @main_loop_thread_lock.synchronize do while @main_loop_generation == current_generation @main_loop_thread_cond.wait(@main_loop_thread_lock) end end end |