Notable addition is logging, interrupt catches and getting line number when a Ruby script errors out.
#!/usr/bin/ruby
###############
##########################
# FastCGI Ruby dispatcher
# (C) Derrick Pallas
# (C) Rizal Kertadjaja
# Original Authors: Derrick Pallas http://derrick.pallas.us/ruby-cgi/
# Modified by: Rizal Kertadjaja http://learnwebstuff.blogspot.com
# License: Academic Free License 3.0
# Version: 2007-06-17
#
require "fcgi"
require "mmap"
require "logger"
maxscripts = 128
maxscripts.freeze
@log_file_path = "/path/to/log/file"
@log_file_path.freeze
class Script
attr_accessor :map
attr_accessor :mod
attr_accessor :use
end
scripts = {}
mytime = File.stat(__FILE__).mtime
def getBinding(cgi,env)
return binding
end
def logger
@logger = Logger.new(@log_file_path)
end
def dispatcher_log(level, msg)
time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S")
logger.send(level, "[#{time_str} :: #{$$}] #{msg}")
rescue Object => log_error
STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n"
STDERR << " #{log_error.class}: #{log_error.message}\n"
end
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
begin
FCGI.each_cgi do cgi
script = cgi.env_table['SCRIPT_FILENAME']
script.freeze
begin
if ( not scripts.key?script or scripts[script].mod < File.stat(script).mtime )
if scripts.key?script
scripts[script].map.munmap
else
scripts[script] = Script.new
end
scripts[script].mod = File.stat(script).mtime
scripts[script].map = Mmap.new script, "r"
end
scripts[script].use = Time.now
Dir.chdir( File.dirname(script) )
catch (:done) do
eval scripts[script].map, getBinding(cgi,cgi.env_table), script if scripts[script].map
end
if scripts.length > maxscripts
begin
killme = scripts.min { a,b a[1].use <=> b[1].use } [0]
scripts[killme].map.munmap
scripts.delete(killme)
rescue Exception
end
end
rescue Exception => bang
dispatcher_error bang
end if (script && File.stat(script).readable?)
if (File.stat(__FILE__).mtime > mytime)
Process.kill 'SIGHUP', Process.pid
mytime = File.stat(__FILE__).mtime
end
end
GC.enable
dispatch_log :info, "terminated gracefully"
rescue Interrupt => interrupt_error
dispatcher_log :info, "terminated by interrupt"
rescue SystemExit => exit_error
dispatcher_log :info, "terminated by explicit exit"
rescue Object => fcgi_error
dispatcher_error fcgi_error, "killed by this error"
end
# END
######