Initialize the FastCGI instance with the path to a crash log detailing unhandled exceptions (default RAILS_ROOT/log/fastcgi.crash.log) and the number of requests to process between garbage collection runs (default nil for normal GC behavior.) Optionally, pass a block which takes this instance as an argument for further configuration.
# File lib/fcgi_handler.rb, line 31 def initialize(log_file_path = nil, gc_request_period = nil) self.log_file_path = log_file_path || "#{RAILS_ROOT}/log/fastcgi.crash.log" self.gc_request_period = gc_request_period # Yield for additional configuration. yield self if block_given? # Safely install signal handlers. install_signal_handlers @app = Dispatcher.new # Start error timestamp at 11 seconds ago. @last_error_on = Time.now - 11 end
# File lib/fcgi_handler.rb, line 47 def process!(provider = FCGI) mark_features! dispatcher_log :info, 'starting' process_each_request provider dispatcher_log :info, 'stopping gracefully' rescue Exception => error case error when SystemExit dispatcher_log :info, 'stopping after explicit exit' when SignalException dispatcher_error error, 'stopping after unhandled signal' else # Retry if exceptions occur more than 10 seconds apart. if Time.now - @last_error_on > 10 @last_error_on = Time.now dispatcher_error error, 'retrying after unhandled exception' retry else dispatcher_error error, 'stopping after unhandled exception within 10 seconds of the last' end end end
# File lib/fcgi_handler.rb, line 236 def close_connection(request) request.finish if request end
# File lib/fcgi_handler.rb, line 126 def dispatcher_error(e, msg = "") error_message = "Dispatcher failed to catch: #{e} (#{e.class})\n" + " #{e.backtrace.join("\n ")}\n#{msg}" dispatcher_log(:error, error_message) end
# File lib/fcgi_handler.rb, line 118 def dispatcher_log(level, msg) time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S") logger.send(level, "[#{time_str} :: #{$$}] #{msg}") rescue Exception => log_error # Logger errors STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n" STDERR << " #{log_error.class}: #{log_error.message}\n" end
# File lib/fcgi_handler.rb, line 163 def exit_handler(signal) dispatcher_log :info, "asked to stop ASAP" if @processing @when_ready = :exit else throw :exit end end
# File lib/fcgi_handler.rb, line 158 def exit_now_handler(signal) dispatcher_log :info, "asked to stop immediately" exit end
# File lib/fcgi_handler.rb, line 228 def gc_countdown if gc_request_period @gc_request_countdown ||= gc_request_period @gc_request_countdown -= 1 run_gc! if @gc_request_countdown <= 0 end end
# File lib/fcgi_handler.rb, line 137 def install_signal_handler(signal, handler = nil) if SIGNALS.include?(signal) && self.class.method_defined?(name = "#{SIGNALS[signal]}_handler") handler ||= method(name).to_proc begin trap(signal, handler) rescue ArgumentError dispatcher_log :warn, "Ignoring unsupported signal #{signal}." end else dispatcher_log :warn, "Ignoring unsupported signal #{signal}." end end
# File lib/fcgi_handler.rb, line 133 def install_signal_handlers GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) } end
# File lib/fcgi_handler.rb, line 114 def logger @logger ||= Logger.new(@log_file_path) end
Make a note of $" so we can safely reload this instance.
# File lib/fcgi_handler.rb, line 213 def mark_features! @features = $".clone end
# File lib/fcgi_handler.rb, line 73 def process_each_request(provider) request = nil catch :exit do provider.each do |request| process_request(request) case when_ready when :reload reload! when :restart close_connection(request) restart! when :exit close_connection(request) throw :exit end end end rescue SignalException => signal raise unless signal.message == 'SIGUSR1' close_connection(request) end
# File lib/fcgi_handler.rb, line 97 def process_request(request) @processing, @when_ready = true, nil gc_countdown with_signal_handler 'USR1' do begin ::Rack::Handler::FastCGI.serve(request, @app) rescue SignalException, SystemExit raise rescue Exception => error dispatcher_error error, 'unhandled dispatch error' end end ensure @processing = false end
# File lib/fcgi_handler.rb, line 205 def reload! run_gc! if gc_request_period restore! @when_ready = nil dispatcher_log :info, "reloaded" end
# File lib/fcgi_handler.rb, line 172 def reload_handler(signal) dispatcher_log :info, "asked to reload ASAP" if @processing @when_ready = :reload else reload! end end
# File lib/fcgi_handler.rb, line 190 def restart! config = ::Config::CONFIG ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT'] command_line = [ruby, $0, ARGV].flatten.join(' ') dispatcher_log :info, "restarted" # close resources as they won't be closed by # the OS when using exec logger.close rescue nil Rails.logger.close rescue nil exec(command_line) end
# File lib/fcgi_handler.rb, line 181 def restart_handler(signal) dispatcher_log :info, "asked to restart ASAP" if @processing @when_ready = :restart else restart! end end
# File lib/fcgi_handler.rb, line 217 def restore! $".replace @features Dispatcher.reset_application! ActionController::Routing::Routes.reload end
Generated with the Darkfish Rdoc Generator 2.