Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 1284

Show
Ignore:
Timestamp:
05/04/05 11:10:13 (4 years ago)
Author:
david
Message:

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]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/railties/CHANGELOG

    r1261 r1284  
    11*SVN* 
     2 
     3 
     4* 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] 
     5 
     6* Made dispatch.fcgi more robust by catching fluke errors and retrying unless its a permanent condition. [Jamis Buck] 
    27 
    38* Added console --profile for profiling an IRB session #1154 [bitsweat] 
  • trunk/railties/dispatches/dispatch.fcgi

    r981 r1284  
    11#!/usr/local/bin/ruby 
     2 
     3def dispatcher_log(level, path,msg) 
     4  Logger.new(path).send(level, msg) 
     5rescue Object => log_error 
     6  STDERR << "Couldn't write to #{path}: #{msg}" 
     7end 
    28 
    39def dispatcher_error(path,e,msg="") 
    410  error_message = 
    511    "[#{Time.now}] Dispatcher failed to catch: #{e} (#{e.class})\n  #{e.backtrace.join("\n  ")}\n#{msg}" 
    6   Logger.new(path).fatal(error_message) 
    7 rescue Object => log_error 
    8   STDERR << "Couldn't write to #{path} (#{e} [#{e.class}])\n" << error_message 
     12  dispatcher_log(:error, path, error_message) 
    913end 
    1014 
     15last_error_on = nil 
    1116begin 
    1217  require File.dirname(__FILE__) + "/../config/environment" 
     
    1520 
    1621  log_file_path = "#{RAILS_ROOT}/log/fastcgi.crash.log" 
     22  dispatcher_log(:info, log_file_path, "fcgi #{$$} starting") 
     23 
     24  # Allow graceful exits by sending the process SIGUSR1. If the process is 
     25  # currently handling a request, the request will be allowed to complete and 
     26  # then will terminate itself. If a request is not being handled, the 
     27  # process is terminated immediately (via #exit). 
     28 
     29  $please_exit_at_your_earliest_convenience = false 
     30  $i_am_currently_processing_a_request = false 
     31  trap("USR1") do 
     32    if $i_am_currently_processing_a_request 
     33      dispatcher_log(:info, log_file_path, "asking #{$$} to terminate ASAP") 
     34      $please_exit_at_your_earliest_convenience = true 
     35    else 
     36      dispatcher_log(:info, log_file_path, "telling #{$$} to terminate NOW") 
     37      exit 
     38    end 
     39  end 
     40 
     41  # Process each request as it comes in, as a pseudo-CGI. 
    1742 
    1843  FCGI.each_cgi do |cgi|  
    1944    begin 
     45      $i_am_currently_processing_a_request = true 
    2046      Dispatcher.dispatch(cgi) 
    21     rescue Object => rails_error 
    22       dispatcher_error(log_file_path, rails_error) 
     47    rescue Object => e 
     48      dispatcher_error(log_file_path, e) 
     49    ensure 
     50      $stdout.flush 
     51      $i_am_currently_processing_a_request = false 
     52      break if $please_exit_at_your_earliest_convenience 
    2353    end 
    2454  end 
     55 
     56  dispatcher_log(:info, log_file_path, "fcgi #{$$} terminated gracefully") 
     57rescue SystemExit => exit_error 
     58  dispatcher_log(:info, log_file_path, "fcgi #{$$} terminated by explicit exit") 
    2559rescue Object => fcgi_error 
    26   dispatcher_error(log_file_path, fcgi_error, "FCGI process #{$$} killed by this error\n") 
     60  # retry on errors that would otherwise have terminated the FCGI process, but 
     61  # only if they occur more than 10 seconds apart. 
     62  if !(SignalException === fcgi_error) && (last_error_on.nil? || last_error_on - Time.now > 10) 
     63    last_error_on = Time.now 
     64    dispatcher_error(log_file_path, fcgi_error, "FCGI process #{$$} almost killed by this error\n") 
     65    retry 
     66  else 
     67    dispatcher_error(log_file_path, fcgi_error, "FCGI process #{$$} killed by this error\n") 
     68  end 
    2769end