Apache 2.2のモジュールとして密かに FastCGIのProxyが開発されているのを発見。
AJP(Apache JServ Protocol)が Apache2.2から標準対応になったように、FastCGI Protocolもその流れに加えられるものと見られる。
svn co http://svn.apache.org/repos/asf/httpd/httpd/branches/fcgi-proxy-dev
で、ブランチをチェックアウトできる。
cd fcgi-proxy-dev/modules/proxy
apxs2 -c mod_proxy_fcgi.c
で、.lib/mod_proxy_fcgi.so が出来るので、これをApacheのモジュールディレクトリに放り込み、httpd.confには
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
のように書いてやる。
後はバーチャルホスト設定の中で
ProxyPass /myfcgiapp fcgi://myfgihost:port
みたいにしてやれば URIに FastCGIのサービスをマッピング出来る。portは省略すると8000番。
現状、UNIX Domain Socketでの接続には対応していない模様。
AJPの場合もそうだが、RewriteRule [P]を使って Proxyの設定をすることもできる。
RewriteEngine on
RewriteRule ^myfcgiapp/(.*) fcgi://myfcgihost/$1 [P]
ProxyPassはバーチャルホスト設定内にしか書けないが RewriteRuleなら .htaccessにも書けるため手軽に URIのマッピングが出来る。
ruby-fcgiで TCPポート8000番を待ち受けるFastCGIサービスを記述した例は下記。
#!/usr/bin/ruby
FCGI_PURE_RUBY=true
require 'fcgi'
require 'socket'
s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
s.bind(Socket.sockaddr_in(8000, "0.0.0.0"))
s.listen(5)
FCGI::Server.new(s).each_request { |request|
request.out.puts "Content-type: text/plain\r\n\r\n"
request.out.puts "Hello ruby-fcgi!\r\n"
}
多くの人は FastCGIサービスを Webサーバからforkてもらう形で利用しているだろうからこの方式は見慣れないとおもう(というかこれだと既にCGIの体裁をしていない)。このやり方の利点は、サービスがWebサーバと必ずしも同一のホストで動作する必要がないため、Apache 2.2のロードバランサ機能と組み合わせてアプリケーションの負荷分散が可能なことなどである。
なお FCGI_PURE_RUBYをtrueにしないと ruby-fcgiは libfcgiを使用するモードで動作する。このモードでは stdin/stdoutを使った入出力しかできないので mod_proxy_fcgiモジュールからの利用はできない。
追記:下記のコードは正しく動作しない。
FCGI::Server.new(s).each_request { |request|
Thread.start { # スレッドでリクエストを処理
request.out.puts "Content-type: text/plain\r\n\r\n"
request.out.puts "Hello ruby-fcgi!\r\n"
request.finish
}
}fcgi.rbはeach_requestに与えたコードブロックが制御を戻すとすぐにリクエストの終了処理を行いソケットを closeしてしまうため。作者の方はマルチスレッドへの対応を課題として認識してはいるようだ。