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 236 236: def close_connection(cgi) 237: cgi.instance_variable_get("@request").finish if cgi 238: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 126 126: def dispatcher_error(e, msg = "") 127: error_message = 128: "Dispatcher failed to catch: #{e} (#{e.class})\n" + 129: " #{e.backtrace.join("\n ")}\n#{msg}" 130: dispatcher_log(:error, error_message) 131: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 118 118: def dispatcher_log(level, msg) 119: time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S") 120: logger.send(level, "[#{time_str} :: #{$$}] #{msg}") 121: rescue Exception => log_error # Logger errors 122: STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n" 123: STDERR << " #{log_error.class}: #{log_error.message}\n" 124: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 163 163: def exit_handler(signal) 164: dispatcher_log :info, "asked to stop ASAP" 165: if @processing 166: @when_ready = :exit 167: else 168: throw :exit 169: end 170: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 158 158: def exit_now_handler(signal) 159: dispatcher_log :info, "asked to stop immediately" 160: exit 161: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 228 228: def gc_countdown 229: if gc_request_period 230: @gc_request_countdown ||= gc_request_period 231: @gc_request_countdown -= 1 232: run_gc! if @gc_request_countdown <= 0 233: end 234: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 137 137: def install_signal_handler(signal, handler = nil) 138: if SIGNALS.include?(signal) && self.class.method_defined?(name = "#{SIGNALS[signal]}_handler") 139: handler ||= method(name).to_proc 140: 141: begin 142: trap(signal, handler) 143: rescue ArgumentError 144: dispatcher_log :warn, "Ignoring unsupported signal #{signal}." 145: end 146: else 147: dispatcher_log :warn, "Ignoring unsupported signal #{signal}." 148: end 149: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 133 133: def install_signal_handlers 134: GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) } 135: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 114 114: def logger 115: @logger ||= Logger.new(@log_file_path) 116: end
Make a note of $" so we can safely reload this instance.
# File vendor/rails/railties/lib/fcgi_handler.rb, line 213 213: def mark_features! 214: @features = $".clone 215: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 73 73: def process_each_request(provider) 74: cgi = nil 75: 76: catch :exit do 77: provider.each_cgi do |cgi| 78: process_request(cgi) 79: 80: case when_ready 81: when :reload 82: reload! 83: when :restart 84: close_connection(cgi) 85: restart! 86: when :exit 87: close_connection(cgi) 88: throw :exit 89: end 90: end 91: end 92: rescue SignalException => signal 93: raise unless signal.message == 'SIGUSR1' 94: close_connection(cgi) 95: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 97 97: def process_request(cgi) 98: @processing, @when_ready = true, nil 99: gc_countdown 100: 101: with_signal_handler 'USR1' do 102: begin 103: Dispatcher.dispatch(cgi) 104: rescue SignalException, SystemExit 105: raise 106: rescue Exception => error 107: dispatcher_error error, 'unhandled dispatch error' 108: end 109: end 110: ensure 111: @processing = false 112: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 205 205: def reload! 206: run_gc! if gc_request_period 207: restore! 208: @when_ready = nil 209: dispatcher_log :info, "reloaded" 210: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 172 172: def reload_handler(signal) 173: dispatcher_log :info, "asked to reload ASAP" 174: if @processing 175: @when_ready = :reload 176: else 177: reload! 178: end 179: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 190 190: def restart! 191: config = ::Config::CONFIG 192: ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT'] 193: command_line = [ruby, $0, ARGV].flatten.join(' ') 194: 195: dispatcher_log :info, "restarted" 196: 197: # close resources as they won't be closed by 198: # the OS when using exec 199: logger.close rescue nil 200: RAILS_DEFAULT_LOGGER.close rescue nil 201: 202: exec(command_line) 203: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 181 181: def restart_handler(signal) 182: dispatcher_log :info, "asked to restart ASAP" 183: if @processing 184: @when_ready = :restart 185: else 186: restart! 187: end 188: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 217 217: def restore! 218: $".replace @features 219: Dispatcher.reset_application! 220: ActionController::Routing::Routes.reload 221: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 223 223: def run_gc! 224: @gc_request_countdown = gc_request_period 225: GC.enable; GC.start; GC.disable 226: end