Windowsがシャットダウンするとき、動作中のrubyプログラムはどうなるのか?

まあ強制終了されるのだけど。
普通、rubyプログラムは外部から強制終了させられるとき(INTシグナルが送られてきた時)はInterrupt例外を吐いて死ぬのだけど、OS自体がシャットダウンするときはどうなるのか?今回はWindows7で確かめてみた。ちなみにRubyruby 2.1.5p273 [i386-mingw32]というのを使った。
こんなプログラムを書いて実験してみた。

  • loop1.rb
while(true) do
  puts "working!"
  sleep 1
end

これを普通にCtrl+Cで強制終了するとまあ、以下のようになる。これは当たり前。

> ruby loop1.rb
working!
working!
working!
loop1.rb:3:in `sleep': Interrupt
  from loop2.rb:3:in `<main>'

今度は実行中にWindowsをシャットダウンしてみる。
シャットダウンした後にもう一度Windowsを立ち上げて実行結果を確かめられるように、標準出力と標準エラー出力をファイルに出すことにした。

> ruby loop1.rb > AAA.TXT 2> BBB.TXT

結果はAAA.TXTもBBB.TXTも空白。なんだそりゃ。
なぜ何も出力されないかを考えてみる。

  1. INTシグナル以外のシグナルが送られて来たことにより強制終了したため、Interrupt例外が発生しなかった。(INT以外のシグナルでも発生するかもしれないけど)
  2. シャットダウンの時は何のシグナルも送ってこず、ただ強制終了させられた。
  3. 何かしらのシグナルが送られてきたが、ruby側で捕捉する間もなく強制終了させられた。

とりあえずシャットダウンの時にシグナルが送られてきて、捕捉されるかどうかだけでも確かめたい。
以下の様なプログラムにしてみた。

  • loop2.rb
trap(:INT) { p "INT";exit }
#trap(:ILL) { p "ILL" }
#trap(:FPE) { p "FPE" }
#trap(:SEGV) { p "SEGV" }
trap(:TERM) { p "TERM";exit }
#trap(:BREAK){ p "BREAK" }
trap(:ABRT) { p "ABRT";exit }
trap(:EXIT) { p "EXIT";exit }

while(true) do
  puts "working!"
  sleep 1
end

リファレンスによれば、WindowsrubyではINT ILL FPE SEGV TERM BREAK ABRT EXITのシグナルが捕捉できる。
http://docs.ruby-lang.org/ja/2.1.0/class/Signal.html
ただし、ILL FPE SEGV BREAKはtrapメソッドの引数に指定すると実行時エラーになるのでコメントにした。
普通に実行してCtrl+Cで強制終了した場合*1は以下の様な出力になる。

> ruby loop2.rb
working!
working!
working!
"INT"
"EXIT"

*2
じゃあさっきと同じようにしてプログラムを起動し、Windowsをシャットダウンしてみる。

> ruby loop2.rb > AAA.TXT 2> BBB.TXT

そして、Windowsを立ち上げてAAA.TXTとBBB.TXTをテキストエディタで開いてみると。。
結果は空白。何にも出力されていなかった。

てなわけでrubyプログラムの実行中にWindowsをシャットダウンした時の動作は、

  • 何のシグナルも送ってこず、ただ強制終了させられる。
  • 何かしらのシグナルが送られるが、ruby側で捕捉する間もなく強制終了させられる。

の2つが濃厚なようです。あと、rubyで捕捉できないシグナルが送られてくる、っていうのも考えられるか。。

追記:2015/3/15
タスクマネージャーから強制終了したらどうなるのか?
気になったので試してみたらシャットダウンの時と同じ動きでした。



以下余談
こんなことを考えたのは、エラーログをなにも吐かずに異常終了したプログラム*3があって、なんとか終了した原因を知りたいというのがありました。やっぱり実行中にPC再起動しちゃったんじゃないかなあ。。WindowsUpdateとかだってあるかもしれんし。という疑いはあるのですが、証拠はありません。
それならOSのシャットダウンをRuby側で捕捉できるようにすれば、動かぬ証拠を記録できるのでは?と考えたのです。しかし結局ダメだった。

*1:本当は強制終了ではなくシグナルを捕捉した上で正常終了する。

*2:最後に”EXIT”が出ているのはINTを捕捉した後、exitメソッドを呼んだことによりEXITシグナルが送られてきたため。

*3:処理が終わるのにすっごく時間がかかる

sinatraとmechanizeを一緒に使うと動かない(動かす方法が悪いので)

sinatraで今WEBアプリを作っている。
WEBアクセスがあったらMechanizeで別のサイトへデータを取りに行く、みたいなの。

require 'sinatra'
require 'mechanize'

get "/" do
  agent = Mechanize.new
  agent.open("http://example.com")
 #とかなんとか
end

で、これを起動しようとするとエラーになる

$ bundle exec ruby web_main.rb
(省略)/gem/ruby/2.1.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:1497:in `start_server': undefined method `run' for HTTP:Module (NoMethodError)
	from (省略)/gem/ruby/2.1.0/gems/sinatra-1.4.5/lib/sinatra/base.rb:1435:in `run!'
	from (省略)/gem/ruby/2.1.0/gems/sinatra-contrib-1.4.2/lib/sinatra/reloader.rb:252:in `run!'
	from (省略)/gem/ruby/2.1.0/gems/sinatra-1.4.5/lib/sinatra/main.rb:25:in `block in <module:Sinatra>'

メソッド名かなんかが競合しているようだ。

解決方法はStackOverflowに。
ruby - Mechanize & Sinatra conflict - Stack Overflow
まとめると、以下のようにすれば良い。

  • 手段その1. WEBハンドラを最上位に書くんじゃなくてクラスでくるんでやる
class MyApp < Sinatra::Base
  get '/' do
    # mechanize stuff
  end
end
  • 手段その2. Sinatraアプリを動かすサーバをWebrickからThinにする。(やり方はわからんがなんか設定すればできた気がする)

まだ試してないが、なるほどなと思った。

追記:Thinを入れるだけで手段その2が実現できる。簡単なのでこっちでやることにした。

Ubuntu ServerのユーザーディレクトリでPHPが使えるようにする。

以下は2014/10/17にはてなダイアリーに投稿した内容だが、ブログトップに表示されないのではてなブログにも転載することにした。
微妙に修正もしている。(元記事:Ubuntu ServerのユーザーディレクトリでPHPが使えるようにする。 - 橋本幸樹の無愛想な日記
まあ自分用のメモなので転載する意味はそれほど無いような気もする。
以下本文。



Ubuntu 10.04.4 LTSだとphpとユーザディレクトリのモジュールを有効にしただけではユーザディレクトリにPHPスクリプトを置いても実行されずにスクリプトがダウンロードされてしまう。

以下の設定ファイルを編集し、apacheを再起動すると動いてくれる。

  • /etc/apache2/mods-available/php5.conf

編集前

<IfModule mod_php5.c>
    <FilesMatch "\.ph(p3?|tml)$">
  SetHandler application/x-httpd-php
    </FilesMatch>
    <FilesMatch "\.phps$">
  SetHandler application/x-httpd-php-source
    </FilesMatch>
    # To re-enable php in user directories comment the following lines
    # (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
    # prevents .htaccess files from disabling it.
    <IfModule mod_userdir.c>
        <Directory /home/*/public_html>
            php_admin_value engine Off
        </Directory>
    </IfModule>
</IfModule>
~                   

編集後

<IfModule mod_php5.c>
    <FilesMatch "\.ph(p3?|tml)$">
  SetHandler application/x-httpd-php
    </FilesMatch>
    <FilesMatch "\.phps$">
  SetHandler application/x-httpd-php-source
    </FilesMatch>
    # To re-enable php in user directories comment the following lines
    # (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
    # prevents .htaccess files from disabling it.
    #<IfModule mod_userdir.c>
    #    <Directory /home/*/public_html>
    #        php_admin_value engine Off
    #    </Directory>
    #</IfModule>
</IfModule>

つまり、"<IfModule mod_userdir.c\>"のブロックをコメントアウトする。
"php_admin_value engine Off"という命令によってユーザディレクトリでのPHPの実行が抑制されているようだが、"php_admin_value engine On"にしてもPHPスクリプトへのアクセス時にサーバーエラーになってしまい実行できない。ブロック全体をコメントアウトまたは削除する必要がある。(よく読むとこのファイルのコメントにそう書いてある。)

CKEditor for WordPressをアップデートしたらボタンのカスタマイズ設定のやり方が微妙に変わっていた

WEB系の人に戻ったので最近はWordPressをいじることもある。

WordPressプラグインとして動作するCKEditor for WordPress というWYSIWYGエディタを4.0から4.4.4にアップデートしたところ、ツールバーボタンの表示のカスタマイズ設定が全部消えてデフォルトに戻っていた。

設定ファイル(ckeditor.confing.js)をバックアップしていたもので上書きしたが、今度はツールバーボタンがひとつも表示されなくなった。それで以下のページなどを見ながらあーでもないこーでもないとやっていた。

CKEditor4のボタンをカスタマイズしてみよう!(WordPress編) | Webcre Archive

 

で、わかったのは設定を入れる変数名が4.0と4.4.4では違うということだった。

つまり、

  • 4.0は config.toolbarGroups または config.toolbar_WordpressFull
  • 4.4.4はconfig.toolbar_WordpressFullのみ

config.toolbarGroupsはデフォルトの設定ファイルにも書かれていて、普通なら設定変更はこれを書き換えるやり方でしたくなると思う。

config.toolbar_WordpressFullの方は設定ファイルの他の部分やCKEditorの設定画面を見ながら類推して気づいた。あちこち検索したページの中にもひょっとしたらあったかもしれないけど。

もともとのうちの設定はconfig.toolbarGroupsに入っていたので4.4.4では何にも表示されないということだった。

このへんの変化について書いてあるドキュメントも特に見つからず、たったこれだけのことでえらい苦労をした。まあこの手の作業ではよくあることだけれど。他にも色々言いたいがもうこれ以上言うまい。疲れた。