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 31 31: def initialize(log_file_path = nil, gc_request_period = nil) 32: self.log_file_path = log_file_path || "#{RAILS_ROOT}/log/fastcgi.crash.log" 33: self.gc_request_period = gc_request_period 34: 35: # Yield for additional configuration. 36: yield self if block_given? 37: 38: # Safely install signal handlers. 39: install_signal_handlers 40: 41: # Start error timestamp at 11 seconds ago. 42: @last_error_on = Time.now - 11 43: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 45 45: def process!(provider = FCGI) 46: mark_features! 47: 48: dispatcher_log :info, 'starting' 49: process_each_request provider 50: dispatcher_log :info, 'stopping gracefully' 51: 52: rescue Exception => error 53: case error 54: when SystemExit 55: dispatcher_log :info, 'stopping after explicit exit' 56: when SignalException 57: dispatcher_error error, 'stopping after unhandled signal' 58: else 59: # Retry if exceptions occur more than 10 seconds apart. 60: if Time.now - @last_error_on > 10 61: @last_error_on = Time.now 62: dispatcher_error error, 'retrying after unhandled exception' 63: retry 64: else 65: dispatcher_error error, 'stopping after unhandled exception within 10 seconds of the last' 66: end 67: end 68: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 234 234: def close_connection(cgi) 235: cgi.instance_variable_get("@request").finish if cgi 236: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 124 124: def dispatcher_error(e, msg = "") 125: error_message = 126: "Dispatcher failed to catch: #{e} (#{e.class})\n" + 127: " #{e.backtrace.join("\n ")}\n#{msg}" 128: dispatcher_log(:error, error_message) 129: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 116 116: def dispatcher_log(level, msg) 117: time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S") 118: logger.send(level, "[#{time_str} :: #{$$}] #{msg}") 119: rescue Exception => log_error # Logger errors 120: STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n" 121: STDERR << " #{log_error.class}: #{log_error.message}\n" 122: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 161 161: def exit_handler(signal) 162: dispatcher_log :info, "asked to stop ASAP" 163: if @processing 164: @when_ready = :exit 165: else 166: throw :exit 167: end 168: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 156 156: def exit_now_handler(signal) 157: dispatcher_log :info, "asked to stop immediately" 158: exit 159: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 226 226: def gc_countdown 227: if gc_request_period 228: @gc_request_countdown ||= gc_request_period 229: @gc_request_countdown -= 1 230: run_gc! if @gc_request_countdown <= 0 231: end 232: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 135 135: def install_signal_handler(signal, handler = nil) 136: if SIGNALS.include?(signal) && self.class.method_defined?(name = "#{SIGNALS[signal]}_handler") 137: handler ||= method(name).to_proc 138: 139: begin 140: trap(signal, handler) 141: rescue ArgumentError 142: dispatcher_log :warn, "Ignoring unsupported signal #{signal}." 143: end 144: else 145: dispatcher_log :warn, "Ignoring unsupported signal #{signal}." 146: end 147: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 131 131: def install_signal_handlers 132: GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) } 133: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 112 112: def logger 113: @logger ||= Logger.new(@log_file_path) 114: end
Make a note of $" so we can safely reload this instance.
# File vendor/rails/railties/lib/fcgi_handler.rb, line 211 211: def mark_features! 212: @features = $".clone 213: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 71 71: def process_each_request(provider) 72: cgi = nil 73: 74: catch :exit do 75: provider.each_cgi do |cgi| 76: process_request(cgi) 77: 78: case when_ready 79: when :reload 80: reload! 81: when :restart 82: close_connection(cgi) 83: restart! 84: when :exit 85: close_connection(cgi) 86: throw :exit 87: end 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: @processing, @when_ready = true, 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: ensure 109: @processing = false 110: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 203 203: def reload! 204: run_gc! if gc_request_period 205: restore! 206: @when_ready = nil 207: dispatcher_log :info, "reloaded" 208: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 170 170: def reload_handler(signal) 171: dispatcher_log :info, "asked to reload ASAP" 172: if @processing 173: @when_ready = :reload 174: else 175: reload! 176: end 177: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 188 188: def restart! 189: config = ::Config::CONFIG 190: ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT'] 191: command_line = [ruby, $0, ARGV].flatten.join(' ') 192: 193: dispatcher_log :info, "restarted" 194: 195: # close resources as they won't be closed by 196: # the OS when using exec 197: logger.close rescue nil 198: Rails.logger.close rescue nil 199: 200: exec(command_line) 201: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 179 179: def restart_handler(signal) 180: dispatcher_log :info, "asked to restart ASAP" 181: if @processing 182: @when_ready = :restart 183: else 184: restart! 185: end 186: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 215 215: def restore! 216: $".replace @features 217: Dispatcher.reset_application! 218: ActionController::Routing::Routes.reload 219: end
# File vendor/rails/railties/lib/fcgi_handler.rb, line 221 221: def run_gc! 222: @gc_request_countdown = gc_request_period 223: GC.enable; GC.start; GC.disable 224: end