From: Brian Candler Date: 2003-03-08T22:16:05+09:00 Subject: Re: DRB and threads --VrqPEDrXMn8OVzN4 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sat, Mar 08, 2003 at 11:38:31AM +0900, ahoward wrote: > > I quite like the Apache/FastCGI approach because the code for allocating > > instances of the backend is already written and hopefully reasonably > > debugged; it can have a fixed or variable number of instances. > > debugged, but not user friendly. i wrote a little wrapper that dealt with > much of the signal handling, and used someone else pattern (i forget whose) to > boot strap a normal cgi objec of off a fcgi object. it's at > > http://groups.google.com/groups?q=ahoward+mod_fcgi+group:comp.lang.ruby&hl=en&lr=&ie=UTF-8&selm=Pine.LNX.4.33.0302121430040.10747-100000%40eli.fsl.noaa.gov&rnum=1 Yes, I found this sufficiently interesting that I kept a copy when you first posted it, so thanks for reminding me! It's [ruby-talk:64468] for a shorter link. Did you find that installing a SIGPIPE handler was actually necessary? According to the mod_fastcgi documentation, mod_fastcgi itself sets this for applications which it spawns; also libfcgi installs an empty signal handler for SIGPIPE as well (OS_SigpipeHandler in libfcgi/os_unix.c) I removed install_traps and sent a kill -PIPE to the spawned process and it didn't seem to blink, so I think it's not actually necessary (but perhaps it is with the pure Ruby version of fcgi) A few other points: * you call '@@server.close' but this ties you to the pure-Ruby implementation; I am using the C version and it doesn't set such an instance variable. This means you can get warnings logged such as mod_fcgi.rb:in `install_traps': uninitialized class variable @@server in MOD_FCGI (NameError) * the trapping of TERM and HUP doesn't work properly for me. What happens is that if I send such a signal to the process, nothing happens (ps shows the same pid) until the next HTTP request comes along, at which point it fails and Apache returns '500 Internal Server Error'. The process is then restarted and it's fine thereafter. I put some file debugging in: $stderr = File.open("/tmp/errs","a") $stderr.sync = true ... trap('SIGHUP') do $stderr.puts "#{Time.now} signals #{@@signals.inspect} handling_request #{@@handling_request.inspect} exit_requested #{@@exit_requested.inspect}" ... What seems to happen is that the trap handler is not even started until the subsequent request comes in, as shown by the timestamp. The process *then* commits suicide (since @@handling_request is still false at that point) and the 500 error occurs. Changing 'exit' to 'exit!' doesn't make any difference either. It's as if the signal is held up in accept() until the next incoming connection arrives. I can't work out why this is the case, but for now just removing 'install_traps' actually gives me much better results, since the process just dies and is respawned straight away. FYI I am running ruby 1.6.8 (2002-12-24) [i386-freebsd4.7] with ruby-fcgi-0.8.1 + fcgi-2.4.0, apache-1.3.27, mod_fastcgi-2.2.12 * I also had to make a few changes to make it load cleanly under ruby -w (attached) Otherwise this all looks very cool, and I actually don't think that it's Apache-specific. SIGPIPE isn't an Apache extension to fastcgi spec, it just closes the socket if it isn't interested in waiting for the response, and the OS generates SIGPIPE. Other fastcgi servers are likely to do the same. As a result, I think that what you've written really belongs in the core FCGI library anyway, i.e. - bootstrapping of a CGI object (maybe FCGI.each_cgi ?) and perhaps also optional graceful shutdown on USR1, if it can be made to work (although that _is_ an Apache feature) Or else at least it can go on the RubyGardenWiki ? Regards, Brian. P.S. Thinking about USR1, I just checked and libfcgi does install a USR1 handler (which sets an interal flag for a graceful abort). However it doesn't work very well if the process is between requests, because it just sits in accept() and catches the signal, so doesn't abort until the next incoming connection occurs, giving a 500 error to the client. --VrqPEDrXMn8OVzN4 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="mod_fcgi.rb.patch" --- mod_fcgi.rb.orig Sat Mar 8 10:06:51 2003 +++ mod_fcgi.rb Sat Mar 8 12:46:08 2003 @@ -59,7 +59,7 @@ if $SAFE > 0 and tmpdir.tainted? tmpdir = '/tmp' end - basename ||= File.basename $0 + basename ||= File.basename($0) n = 0 while true begin @@ -96,7 +96,7 @@ def initialize(request, *args) self.class.remove_params @request = request - super (*args) + super(*args) @args = *args end def args @@ -134,13 +134,13 @@ # user signal to reload application # does a clean shutdown after which # the fcgi_pm will reload of source file - trap ('SIGHUP') do + trap('SIGHUP') do unless @@signals.size > 0 @@signals << 'SIGHUP' if @@handling_request @@exit_requested = true else - @@server.close + @@server.close if defined? @@server exit end end @@ -149,24 +149,24 @@ # 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 + trap('SIGUSR1') do unless @@signals.size > 0 @@signals << 'SIGUSR1' if @@handling_request @@exit_requested = true else - @@server.close + @@server.close if defined? @@server exit end end end # see above note. - # when no other signals pedning, simply exit quickly - trap ('SIGTERM') do + # when no other signals pending, simply exit quickly + trap('SIGTERM') do unless @@signals.size > 0 @@signals << 'SIGTERM' - @@server.close + @@server.close if defined? @@server exit end end @@ -174,7 +174,7 @@ # 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 + trap('SIGPIPE') do # nothing end @@ -182,15 +182,15 @@ end def each (*args) - install_traps + #install_traps can be called by the user first while request = accept handle_request { if block_given? - yield (CGI.new (request, *args)) + yield(CGI.new(request, *args)) request.finish end } - exit if @@exit_requested + break if @@exit_requested end end --VrqPEDrXMn8OVzN4--