arton/ennou — pull request #10 by nagachika (2012-10-25 02:08:11+00:00)
Title: retry when rb_w32_wait_events() return with errno == EINTR.

Windows Azure 上で NougakuDoCompanion+能楽堂でRailsアプリケーションを起動していると、不定期にリクエストを受け付けない状態になることがありました。
NougakuDoCompanionは起動していますが、タスクマネージャで確認すると ruby のプロセスが(controller のみ残して)終了してしまっているようでした。(複数プロセス起動する設定で利用していました)。

rack/handler/ennoumu.rb の l.58 rescue Interrupt の部分にデバッグプリントを挿入して手動で rackup を実行してみたところ以下のようなメッセージとバックトレースを得ました。

[2012-10-24 09:27:23] ERROR wait HttpReceiveHttpRequest (10004)
Interrupt
C:/NougakuDoCompanion/Runtime/Working/NougakuDo/lib/ruby/site_ruby/1.9.1/rack/handler/ennoumu.rb:55:in `wait'
C:/NougakuDoCompanion/Runtime/Working/NougakuDo/lib/ruby/site_ruby/1.9.1/rack/handler/ennoumu.rb:55:in `block (2 levels) in run'
C:/NougakuDoCompanion/Runtime/Working/NougakuDo/lib/ruby/site_ruby/1.9.1/rack/handler/ennoumu.rb:53:in `loop'
C:/NougakuDoCompanion/Runtime/Working/NougakuDo/lib/ruby/site_ruby/1.9.1/rack/handler/ennoumu.rb:53:in `block in run'
C:/NougakuDoCompanion/Runtime/Working/NougakuDo/lib/ruby/site_ruby/1.9.1/rack/handler/ennoumu.rb:28:in `open'
C:/NougakuDoCompanion/Runtime/Working/NougakuDo/lib/ruby/site_ruby/1.9.1/rack/handler/ennoumu.rb:28:in `run'
C:/NougakuDoCompanion/Application/Working/app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:265:in `start'
C:/NougakuDoCompanion/Application/Working/app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:137:in `start'
C:/NougakuDoCompanion/Application/Working/app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/bin/rackup:4:in `'
c:/NougakuDoCompanion/Runtime/Working/NougakuDo/bin/rackup:19:in `load'
c:/NougakuDoCompanion/Runtime/Working/NougakuDo/bin/rackup:19:in `

'
[2012-10-24 09:27:23] INFO Ennou(1.1.6) stop service for http://+:80 pid=1996

この例外メッセージとバックトレースからから、原因は ext/ennou/ennou.c の wait_io() で rb_w32_wait_events() が WAIT_OBJECT_0 + 1 を返した時に Interrupt を raise しているためだと推測できます。
irc で usa さんや ko1 さんに相談してみたところ rb_w32_wait_events() が WAIT_OBJECT_0 + 1 を返すのは割り込みを受けた時で、この割り込みはシグナル(Ctrl-C 相当)の受信の他にタイマースレッドからの割り込み、GC 後のファイナライザ実行の要求、別のスレッドからの Thread#raise での例外発生などがありえます。
このうちタイマーの割り込みやファイナライザ実行の場合は再度 rb_w32_wait_events() を呼び出して続行すべきではないかと思います。