Class | RailsFCGIHandler |
In: |
vendor/rails/railties/lib/fcgi_handler.rb
|
Parent: | Object |
SIGNALS | = | { 'HUP' => :reload, 'INT' => :exit_now, 'TERM' => :exit_now, 'USR1' => :exit, 'USR2' => :restart |
GLOBAL_SIGNALS | = | SIGNALS.keys - %w(USR1) |
gc_request_period | [RW] | |
log_file_path | [RW] | |
when_ready | [R] |
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 vendor/rails/railties/lib/fcgi_handler.rb, line 32 32: def initialize(log_file_path = nil, gc_request_period = nil) 33: self.log_file_path = log_file_path || "#{RAILS_ROOT}/log/fastcgi.crash.log" 34: self.gc_request_period = gc_request_period 35: 36: # Yield for additional configuration. 37: yield self if block_given? 38: 39: # Safely install signal handlers. 40: install_signal_handlers 41: 42: # Start error timestamp at 11 seconds ago. 43: @last_error_on = Time.now - 11 44: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 46 46: def process!(provider = FCGI) 47: mark_features! 48: 49: dispatcher_log :info, 'starting' 50: process_each_request provider 51: dispatcher_log :info, 'stopping gracefully' 52: 53: rescue Exception => error 54: case error 55: when SystemExit 56: dispatcher_log :info, 'stopping after explicit exit' 57: when SignalException 58: dispatcher_error error, 'stopping after unhandled signal' 59: else 60: # Retry if exceptions occur more than 10 seconds apart. 61: if Time.now - @last_error_on > 10 62: @last_error_on = Time.now 63: dispatcher_error error, 'retrying after unhandled exception' 64: retry 65: else 66: dispatcher_error error, 'stopping after unhandled exception within 10 seconds of the last' 67: end 68: end 69: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 220 220: def close_connection(cgi) 221: cgi.instance_variable_get("@request").finish if cgi 222: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 122 122: def dispatcher_error(e, msg = "") 123: error_message = 124: "Dispatcher failed to catch: #{e} (#{e.class})\n" + 125: " #{e.backtrace.join("\n ")}\n#{msg}" 126: dispatcher_log(:error, error_message) 127: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 114 114: def dispatcher_log(level, msg) 115: time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S") 116: logger.send(level, "[#{time_str} :: #{$$}] #{msg}") 117: rescue Exception => log_error # Logger errors 118: STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n" 119: STDERR << " #{log_error.class}: #{log_error.message}\n" 120: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 159 159: def exit_handler(signal) 160: dispatcher_log :info, "asked to stop ASAP" 161: @when_ready = :exit 162: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 154 154: def exit_now_handler(signal) 155: dispatcher_log :info, "asked to stop immediately" 156: exit 157: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 212 212: def gc_countdown 213: if gc_request_period 214: @gc_request_countdown ||= gc_request_period 215: @gc_request_countdown -= 1 216: run_gc! if @gc_request_countdown <= 0 217: end 218: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 133 133: def install_signal_handler(signal, handler = nil) 134: if SIGNALS.include?(signal) && self.class.method_defined?(name = "#{SIGNALS[signal]}_handler") 135: handler ||= method(name).to_proc 136: 137: begin 138: trap(signal, handler) 139: rescue ArgumentError 140: dispatcher_log :warn, "Ignoring unsupported signal #{signal}." 141: end 142: else 143: dispatcher_log :warn, "Ignoring unsupported signal #{signal}." 144: end 145: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 129 129: def install_signal_handlers 130: GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) } 131: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 110 110: def logger 111: @logger ||= Logger.new(@log_file_path) 112: end
Make a note of $" so we can safely reload this instance.
# File vendor/rails/railties/lib/fcgi_handler.rb, line 197 197: def mark_features! 198: @features = $".clone 199: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 73 73: def process_each_request(provider) 74: cgi = nil 75: 76: provider.each_cgi do |cgi| 77: process_request(cgi) 78: 79: case when_ready 80: when :reload 81: reload! 82: when :restart 83: close_connection(cgi) 84: restart! 85: when :exit 86: close_connection(cgi) 87: break 88: end 89: end 90: rescue SignalException => signal 91: raise unless signal.message == 'SIGUSR1' 92: close_connection(cgi) 93: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 95 95: def process_request(cgi) 96: @when_ready = nil 97: gc_countdown 98: 99: with_signal_handler 'USR1' do 100: begin 101: Dispatcher.dispatch(cgi) 102: rescue SignalException, SystemExit 103: raise 104: rescue Exception => error 105: dispatcher_error error, 'unhandled dispatch error' 106: end 107: end 108: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 189 189: def reload! 190: run_gc! if gc_request_period 191: restore! 192: @when_ready = nil 193: dispatcher_log :info, "reloaded" 194: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 164 164: def reload_handler(signal) 165: dispatcher_log :info, "asked to reload ASAP" 166: @when_ready = :reload 167: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 174 174: def restart! 175: config = ::Config::CONFIG 176: ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT'] 177: command_line = [ruby, $0, ARGV].flatten.join(' ') 178: 179: dispatcher_log :info, "restarted" 180: 181: # close resources as they won't be closed by 182: # the OS when using exec 183: logger.close rescue nil 184: RAILS_DEFAULT_LOGGER.close rescue nil 185: 186: exec(command_line) 187: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 169 169: def restart_handler(signal) 170: dispatcher_log :info, "asked to restart ASAP" 171: @when_ready = :restart 172: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 201 201: def restore! 202: $".replace @features 203: Dispatcher.reset_application! 204: ActionController::Routing::Routes.reload 205: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 207 207: def run_gc! 208: @gc_request_countdown = gc_request_period 209: GC.enable; GC.start; GC.disable 210: end