Class MOD_FCGI < FCGI

rubyists-

i’ve collected some usefull examples and added some signal handling to the
fcgi package written by moon wolf. if any one has experience using fcgi out
there i appreciate any comments. highlights are

* reload any application using 'kill -HUP pid' w/o hanging apache
* gracefull shutdown from confusing SIGUSR1/SIGHUP combo sent by
  apache/mod_fastcgi to fcgi programs
* clean exit on 'kill -TERM pid'
* each method which provides a CGI object

eg of use

MOD_FCGI.each(‘html3’) do |cgi|
content = ‘’
cgi.env_table.each do |k,v|
content << “#{k} → #{v}
\n”
end
cgi.out { cgi.html { cgi.body { content } } }
end

ps. this is named MOD_FCGI because, AFAIK this signal handling is specific to
apache’s mod_fastcgi

file : mod_fcgi.rb
----CUT----
require ‘fcgi’
require ‘cgi’
require ‘ftools’

class MOD_FCGI < FCGI

class Log < File
def tmpnam basename = nil,
tmpdir = ENV[‘TMPDIR’]||ENV[‘TMP’]||ENV[‘TEMP’]||‘/tmp’
if $SAFE > 0 and tmpdir.tainted?
tmpdir = ‘/tmp’
end
basename ||= File.basename $0
n = 0
while true
begin
path = sprintf(‘%s/%s%d.%d’, tmpdir, basename, $$, n)
@_lock = path + ‘.lock’
unless File.exist?(path) or File.exist?(@_lock)
Dir.mkdir(@_lock)
break
end
rescue
raise “cannot generate tempfile `%s’” % path if n >= 16
end
n += 1
end
path
end
def initialize path = tmpnam, mode = ‘w+’, &block
super path, mode, &block
Dir.rmdir(@_lock) if defined? @_lock
self.sync = true
end
end

enable CGI to bootstrap off of an FCGI request

class CGI < ::CGI
class << self
def remove_params
if (const_defined?(:CGI_PARAMS))
remove_const(:CGI_PARAMS)
remove_const(:CGI_COOKIES)
end
end
end
def initialize(request, *args)
self.class.remove_params
@request = request
super (*args)
@args = *args
end
def args
@args
end
def env_table
@request.env
end
def stdinput
@request.in
end
def stdoutput
@request.out
end
end

initialize mod_fcgi

@@handling_request = false
@@exit_requested = false
@@traps_installed = false
@@signals =

class << self
def handle_request
@@handling_request = true
yield if block_given?
ensure
@@handling_request = false
end

def install_traps
  return if @@traps_installed

  # user signal to reload application
  # does a clean shutdown after which
  # the fcgi_pm will reload of source file
  trap ('SIGHUP') do
unless @@signals.size > 0
  @@signals << 'SIGHUP'
  if @@handling_request
    @@exit_requested = true
  else
    @@server.close
    exit
  end
end
  end

  # sent from apache to do clean shutdown
  # note that a sigterm could be sent from fcgi_pm
  # AFTER this!  we handle only one of them!
  trap ('SIGUSR1') do
unless @@signals.size > 0
  @@signals << 'SIGUSR1'
  if @@handling_request
    @@exit_requested = true
  else
    @@server.close
    exit
  end
end
  end

  # see above note.
  # when no other signals pedning, simply exit quickly
  trap ('SIGTERM') do
unless @@signals.size > 0
  @@signals << 'SIGTERM'
  @@server.close
  exit
end
  end

  # sent from mod_fcgi when client aborts request
  # we simply ignore this for now, although some smarts could be
  # added to abort the present request and resume accepting...
  trap ('SIGPIPE') do
# nothing
  end

  @@traps_installed = true
end

def each (*args)
  install_traps
  while request = accept
handle_request {
  if block_given?
    yield (CGI.new (request, *args))
    request.finish
  end
}
exit if @@exit_requested
  end
end

alias each_request each

end
end
----CUT----

-a

···

====================================

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================