Skip to content
Browse files

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
  • Loading branch information...
1 parent ac44be3 commit 6c473eb410a959607ee5f4a5c8597b684f1827c0 @dhh dhh committed May 4, 2005
Showing with 53 additions and 6 deletions.
  1. +5 −0 railties/CHANGELOG
  2. +48 −6 railties/dispatches/dispatch.fcgi
View
5 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]
View
54 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

0 comments on commit 6c473eb

Please sign in to comment.
Something went wrong with that request. Please try again.