--W/nzBZO5zC0uMSeA Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sun, Mar 09, 2003 at 06:40:35PM +0900, ahoward wrote: > On Sun, 9 Mar 2003, Brian Candler wrote: > > > 'require fcgi.rb' pulls in the C version if you have it, otherwise it loads > > the Ruby version. > > doesn't this always require 'fcgi.rb'? i mean, isn't only > > require 'fcgi' > > allowed to chose the *.so over the *.rb? No - it is fcgi.rb which in turn tries to do require fcgi.so, and catches the exception if that fails, in which case it builds the Ruby classes itself. So require 'fcgi' and require 'fcgi.rb' are identical. > > > > * 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 checked this out a little using strace - looks like accept (or calls before > accept) are catching everything so there's not much to be done : > > [howardat@dhcppc1 fcgi-bin]# strace -p 10511 > accept(0, 0xbfffe1ac, [112]) ERESTARTSYS (To be restarted) > --- SIGUSR2 (User defined signal 2) --- > sigreturn() (mask now []) > accept(0, > > same goes for HUP, USR1, etc. That's what I'd expect - well, actually I'd expect EINTR. Poking around FreeBSD header files, there's no ERESTARTSYS but there's an ERESTART which is used internally by the kernel, so I guess certain types of syscall are automatically restarted. Looks like I'll need to play to find out whether accept() works that way. > > - with install_traps: I get the hanging behaviour as described above > > > > - with install_traps commented out: the process dies immediately on > > receipt of TERM or HUP as expected (although if it were in the middle of > > processing a request, it would bomb out without tidying up rather than > > finish the request) > > i think sending SIGHUP and having one request fail is about a good as it gets > ;-( > > i'm not sure what the alternative would be... Don't trap the SIGHUP. The child dies straight away, it gets respawned straight away by Apache (which will keep a minimum of one child per fcgi around unless you configure it otherwise), so the next request is handled successfully. > > FYI I am currently working on adding FCGI server support to druby (there is > > already a HTTP client in samples/http0.rb). Will let you know if I get it to > > work! > > to what end? i mean, what would be the point of having a distributed fastcgi > process? not that there isn't a point, i'm just wondering what you're on > about? I mean using the drb protocol over HTTP as an API: e.g. front-end server talks to the world, and talks DRB-over-HTTP to the back end system, which has a pool of database processes run under fastcgi. It requires Ruby at both ends of course, but it should be a darned sight faster than SOAP or YAML/OKAY, and is *so* easy to use because you just make object calls on the front-end (which magically perform actions on the backend) > one thing which really needs addressed with fcgi is a way to run from a tty so > you can enter params and see the html (or error messages) come blasting back > out... not being able to do this is a real pain when debugging. It can be made automatic. The C library provides a function FCGX_IsCGI() which lets you detect whether you're running under a fastcgi environment or not. (Alternatively, you could write a shell which popen's a fastcgi process and talks fastcgi protocol to it) Anyway, I did manage to get DRB/HTTP to work, but I've now been waylaid looking at performance problems. Firstly, my server was only handling about 10 requests per second, even for plain HTML pages. I finally solved this by setting the TCP_NODELAY socket option (see attached) Interestingly, the Ruby MOD_FCGI/CGI module itself isn't particularly speedly when compared with raw fcgi: Test 1: (MOD_FCGI) #!/usr/local/bin/ruby require 'mod_fcgi' MOD_FCGI.each('html3') do |cgi| cgi.out { "Minimal\n" } end Test 2: (raw FCGI) #!/usr/local/bin/ruby require 'fcgi' FCGI.each { |req| req.out.print "Content-Type: text/plain\n\nMinimal\n" req.finish } Request/response cycle times: - plain HTML page 0.00486 secs - test 1 0.0744 secs - test 2 0.00666 secs (> 10 times faster) So may be worth doing some profiling of the CGI module. (This doesn't seem to be a TCP_NODELAY problem: trussing the code shows it read()ing a FCGI request over the socket, and the write()ing the response back 0.07 seconds later, so it does appear to be Ruby processing) This I'm happy with. What I'm not happy with, under Solaris, is a strange bug where *normal* CGI requests can take up to 3 seconds to complete. I did once manage to capture this with truss, it seemed to be doing alarm(3) sigsuspend ... sleeps here ... woken by the alarm signal However, since today, running a truss on the child which is handling the requests makes the problem go away :-( In fact, a 'normal' CGI of the form #!/bin/sh echo "Content-Type: text/html" echo "" echo "Hello" actually executes faster (0.035 secs) than the Ruby mod_fcgi (0.086 secs) although fcgi is still faster (0.022 secs) *if* truss is in place. With trussing turned off, the above shell script takes an average of 1.5 seconds per iteration. Argh! Anyway, that's either an Apache or a Solaris problem, and hence off-topic for this list (although I'd be very happy to hear the solution if anyone knows it :-) FYI, with DRb over HTTP I am managing about 20 RPC exchanges per second, with a reasonably substantial object being returned, and a DBI query thrown in as part of the request processing. That I'm _very_ happy with. Regards, Brian. --W/nzBZO5zC0uMSeA Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="hithtml.rb" #!/usr/local/bin/ruby require 'net/http' require 'uri' TEST [ 'http://127.0.0.1/index.html' ], [ 'http://127.0.0.1/fcgi-bin/ftest.cgi' ], [ 'http://127.0.0.1/fcgi-bin/ftest2.cgi' ], ] N 0 PERSIST rue $defout.sync ue TEST.each do |test| it RI.parse(test[0]) puts "Req:\t#{it.host},#{it.port},#{it.path}" GC.disable a et::HTTP.new(it.host, it.port || 80) if PERSIST a.start a.socket.socket.setsockopt(6, Socket::TCP_NODELAY, 1) # <<<< FOR UNIX end r .get(it.path) puts r ## want to check content is correct? start ime.now N.times { print "." ## progress info r .get(it.path) } puts "\nTime:\t#{(Time.now - start)/N}" puts a.finish if PERSIST GC.enable GC.start end --W/nzBZO5zC0uMSeA--