diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2005-05-04 11:10:13 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2005-05-04 11:10:13 +0000 |
commit | 6c473eb410a959607ee5f4a5c8597b684f1827c0 (patch) | |
tree | 959e0f4d150e38cb35f4e5597cb29e191550bb4b | |
parent | ac44be3494a846468b6cefa21fa38ff953fc6de9 (diff) | |
download | rails-6c473eb410a959607ee5f4a5c8597b684f1827c0.tar.gz rails-6c473eb410a959607ee5f4a5c8597b684f1827c0.tar.bz2 rails-6c473eb410a959607ee5f4a5c8597b684f1827c0.zip |
Made dispatch.fcgi more robust by catching fluke errors and retrying unless its a permanent condition. [Jamis Buck] Allow graceful exits for dispatch.fcgi processes by sending a 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). This basically works like restart graceful on Apache. [Jamis Buck]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1284 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
-rw-r--r-- | railties/CHANGELOG | 5 | ||||
-rwxr-xr-x | railties/dispatches/dispatch.fcgi | 54 |
2 files changed, 53 insertions, 6 deletions
diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 5664206ed0..f98c57459d 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,5 +1,10 @@ *SVN* + +* Allow graceful exits for dispatch.fcgi processes by sending a 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). This basically works like restart graceful on Apache. [Jamis Buck] + +* Made dispatch.fcgi more robust by catching fluke errors and retrying unless its a permanent condition. [Jamis Buck] + * Added console --profile for profiling an IRB session #1154 [bitsweat] * Changed console_sandbox into console --sandbox #1154 [bitsweat] 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 |