diff options
Diffstat (limited to 'railties/dispatches/dispatch.fcgi')
-rwxr-xr-x | railties/dispatches/dispatch.fcgi | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/railties/dispatches/dispatch.fcgi b/railties/dispatches/dispatch.fcgi index 683a61f4c9..34a99a7105 100755 --- a/railties/dispatches/dispatch.fcgi +++ b/railties/dispatches/dispatch.fcgi @@ -1,27 +1,69 @@ #!/usr/local/bin/ruby +def dispatcher_log(level, path,msg) + Logger.new(path).send(level, msg) +rescue Object => log_error + STDERR << "Couldn't write to #{path}: #{msg}" +end + def dispatcher_error(path,e,msg="") error_message = "[#{Time.now}] Dispatcher failed to catch: #{e} (#{e.class})\n #{e.backtrace.join("\n ")}\n#{msg}" - Logger.new(path).fatal(error_message) -rescue Object => log_error - STDERR << "Couldn't write to #{path} (#{e} [#{e.class}])\n" << error_message + dispatcher_log(:error, path, error_message) end +last_error_on = nil begin require File.dirname(__FILE__) + "/../config/environment" require 'dispatcher' require 'fcgi' log_file_path = "#{RAILS_ROOT}/log/fastcgi.crash.log" + dispatcher_log(:info, log_file_path, "fcgi #{$$} starting") + + # Allow graceful exits by sending the process SIGUSR1. If the process is + # currently handling a request, the request will be allowed to complete and + # then will terminate itself. If a request is not being handled, the + # process is terminated immediately (via #exit). + + $please_exit_at_your_earliest_convenience = false + $i_am_currently_processing_a_request = false + trap("USR1") do + if $i_am_currently_processing_a_request + dispatcher_log(:info, log_file_path, "asking #{$$} to terminate ASAP") + $please_exit_at_your_earliest_convenience = true + else + dispatcher_log(:info, log_file_path, "telling #{$$} to terminate NOW") + exit + end + end + + # Process each request as it comes in, as a pseudo-CGI. FCGI.each_cgi do |cgi| begin + $i_am_currently_processing_a_request = true Dispatcher.dispatch(cgi) - rescue Object => rails_error - dispatcher_error(log_file_path, rails_error) + rescue Object => e + dispatcher_error(log_file_path, e) + ensure + $stdout.flush + $i_am_currently_processing_a_request = false + break if $please_exit_at_your_earliest_convenience end end + + dispatcher_log(:info, log_file_path, "fcgi #{$$} terminated gracefully") +rescue SystemExit => exit_error + dispatcher_log(:info, log_file_path, "fcgi #{$$} terminated by explicit exit") rescue Object => fcgi_error - dispatcher_error(log_file_path, fcgi_error, "FCGI process #{$$} killed by this error\n") + # retry on errors that would otherwise have terminated the FCGI process, but + # only if they occur more than 10 seconds apart. + if !(SignalException === fcgi_error) && (last_error_on.nil? || last_error_on - Time.now > 10) + last_error_on = Time.now + dispatcher_error(log_file_path, fcgi_error, "FCGI process #{$$} almost killed by this error\n") + retry + else + dispatcher_error(log_file_path, fcgi_error, "FCGI process #{$$} killed by this error\n") + end end
\ No newline at end of file |