FastCGI拡張がSegmentation faultを発生させる?(続き)

さて、Ruby-FastCGIコンポーネントを使用するとSegmentation faultが発生する件の続きだ。
まずは状況を整理しよう

  • RubyForIISをインストールするとアクション実行時にSegmentation fault
  • RubyForIISを除去するとSegmentation faultは発生しない

では、RubyForIISでインストールされるファイルを全て列挙してみよう。(Rubyは1.8.7-pl72を使用)

C:\Windows\System32\libfcgi.dll
$RUBY_HOME\lib\ruby\site_ruby\1.8\auto-reload.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\fcgi.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\erb-run.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\eruby-debug.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\eruby-run.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\query.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\rd2html.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\registry.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\ruby-debug.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\apache\ruby-run.rb
$RUBY_HOME\lib\ruby\site_ruby\1.8\i386-msvcrt\fcgi.so
$RUBY_HOME\lib\ruby\site_ruby\1.8\i386-msvcrt\mysql.so

libfcgi.dllはIISFastCGI拡張と直接通信するモジュールだろう。ここでエラーがあった場合はRubyの外になるはずなので、今回の犯人捜しからは除外する。また、Apacheに関するスクリプトもインストールされるのだが、無関係なのでこれも除外。

そうなるとこの中でRubyがSegmentation faultを起こす確率が高いのは、拡張モジュールとして使用される共有オブジェクト(拡張子".so")だろう。RubyForIISでは二つの共有オブジェクトがインストールされる。

fcgi.so
mysql.so

最初のfcgiはlibfcgi.dllへの橋渡しか。もう一つのmysql.soは何をしているのだろう。そもそもこれはmysqlアダプタと共にインストールされるsoと同じ名前のものだ。RubyForIISのREAD MEを見ても

This distribution contains:
   * Apache mod_fastcgi module (fcgi 2.4.0, mod_fastcgi 2.4.2, ruby-fcgi 0.8.6).
   * Apache mod_ruby module (mod_ruby 2.4.0).
   * Native mysql extension (mysql-ruby-2.6).

としか書いていない。ただ、mysql-rubyのドキュメントを見るに、配布されているのはとみたまさひろ氏が開発されたものなので、これは除去しても問題なさそうだ。
ものの試しということで、この二つのファイルを$RUBY_HOME\lib\ruby\site_ruby\1.8\i386-msvcrt\から除去してWEBRickを起動してアプリケーションを動作させたのだが、何度リロードしてもSegmentation faultは発生しなかった。そして、fcgi.soを除去してmysql.soだけを残した所、同Segmentation faultが発生したのである。

最初はデータベースに関わるライブラリィが問題に関わっている等これ程にも思わなかったのだが、テストに使用したアプリケーションはdatabase.ymlをインストール済みのMySQL環境に合わせており、scaffoldではなくともなんらかの経路で、本来gemでアダプタと共にインストールされたmysql.soではなく、RubyForIISでインストールされた古いmysql.soがロードされたのだろう。

一応念のためSegmentation faultが発生した時点で同共有オブジェクトがRubyから使われていることを確かめてみよう。

handleコマンドは以前のエントリでも紹介したが、現在ファイルのハンドルを保持している(ファイルを開いている)プロセスを検索することができるものだ。

C:\Windows\system32>handle mysql.so

Handle v3.42
Copyright (C) 1997-2008 Mark Russinovich
Sysinternals - www.sysinternals.com

ruby.exe           pid: 4212    294: E:\ruby\lib\ruby\site_ruby\1.8\i386-msvcrt\mysql.so

ビンゴ!!
Rubyが知識が無いので現時点では推測でしかないが、なんらかの理由でRubyForIISでインストールされた"OutofDate"なmysql.soがロードされていることが証明された。
どうやらRubyの世界でもWin32である以上、共有ライブラリィ地獄は存在しているようだ。

これでようやく、本当にRailアプリケーションをIIS7 FastCGIホスティングできたといえそうだ。とはいえ、Rubyの世界では他のプラットホームに比べてWindows環境での検証は決して進んでいるとは言えない様なので、本当に安定するかどうか、暫く動かして様子を見ていくしかないだろう。

それとは別に上記の環境( Windows + IIS + FastCGI + Ruby on Rails )で長期間稼働している事例が無いか調べてみよう。