hatena_bookmark_entry.rb の導入顛末記

以前 hatena_bookmark_entry.rb (はてブ人気エントリ表示プラグイン) を導入したと書いた [2007-07-16].導入後,しばらく不安定だったのだけど,作者のまちゅさんのご協力を得て,原因究明と対策を行った.ちょっと自己満足エントリになるが,一応まとめておく.



不安定というのは,導入後しばらくほったらかしにしておくといつの間にか人気エントリリストが表示されなくなるという現象.このプラグインはリストのキャッシュを生成してリクエストがあるとそれを表示する仕組みなんだけど,調べてみるとどうもキャッシュがいつの間にか壊れるらしい.

不思議なのは,キャッシュの取得タイミングが update_proc 実行時に限られているにも関わらず,こちらが日記の更新をしないのに勝手にキャッシュが壊れるということ.しかし update_proc は実はツッコミ投稿時にも実行されることをまちゅさんが指摘してくださった.なので,ツッコミスパムが来た時に何か起こっている可能性がある.



そこで,以下の実験を行った.

1.まちゅさんの「ツッコミスパム襲来時に何らかの例外が発生している可能性がある」という指摘により,

-    rescue TimeoutError => e
+    rescue

のように TimeoutError 以外の例外も捕捉してみた.しかし症状は変化せず.



2.例外発生時は db.abort してデータベースの更新を取り止めてるけど,あえて db.commit してみたらどうなるだろう? → 変化せず.

このあたりから,もしかしてそもそも例外が発生してるわけではないのかも? と思い始める.

念のため,壊れたキャッシュ (bookmark.dat) をよく調べると,最初の行に count という文字列が出ている.これは,少なくとも db[sort].push は実行されていることを強く示唆している.

…もしかしてはてブから取得している RSS が既に壊れてたりするのでは?



3.というわけで,はてブから取得する RSS を調べてみる.

          doc = REXML::Document.new(f.readlines.join("\n"))
+         foo=File.open("foo.txt",'w')
+         foo.puts doc
+         foo.close
          doc.elements.each('rdf:RDF/item') do |item|

として,foo.txt に RSS を吐かせてみたところ,なんと の中身がまったく抜け落ちたものになっていた.RSS としては valid なため,特にエラーが発生しなかったと思われる.



うーむ.はてブ側の問題だったか….

ツッコミスパム連続襲来,はてブへの連続リクエストにより空の RSS が返るという可能性が高い (ただし実証できたわけではない.手元ではてブに連続してリクエストするスクリプトを試しに走らせてみたが,取得した RSS は正常だった).


というわけで,ツッコミ時はキャッシュ取得を行わず,日記更新時のみに取得するような改変を施すことにした.既存のプラグインなどから推測して,どうも @mode で更新時のステータスを保持しているようなので,

@mode が append (日記追加時) あるいは replace (日記更新時) にのみこのプラグインが実行されるよう,

add_update_proc do
+if @mode == 'append' or @mode == 'replace' then
  begin
    sort = @conf['hatena_bookmark_entry.sort']
    hatena_bookmark_update_entry(@cache_path, @conf.base_url, @conf.html_title, 
sort)
  rescue
+  end
end

とした.これでとりあえず安定して動くようになった.

よしよし,Ruby も少しずつではあるがコードが読めるようになってきた.楽しくなってきたぞ.



最後に,今回の問題に対処したバージョンをまちゅさんがリリースしてくださいました (プラグイン名も hatena_bookmark_popular.rb に改名されました).リファクタリングのほか,コマンドラインからの更新機能など新機能も追加.どうもありがとうございます!

というわけで,上記の ad hoc な修正でなくこの新バージョンを使うことをお勧めします.