まちゅダイアリー

tDiary を Google App Engine で動かしてみた

2010-05-29

hsbtさんとこ経由で、kdmsnrさんがtDiaryをherokuで動かしていることを知った。 heroku は Ruby 専用のホスティングサイト。 Ruby だったら何でも動くということはなく、制限がある。

そのため、 tDiary の Rack 対応版 + IOのDataMapper対応版で動いている。 と、ここまで動いているんだったら、 Google App Engine (GAE/JRuby) でも動くんじゃないかと思って試してみた。

結果

http://tdiary-machu.appspot.com/ で、一応動くところまではできた。でも、プラグインはすべて無効にしている。

事前準備

10分ではじめる GAE/JRuby を読み返して手順を思い出す。

$ sudo gem install google-appengine
$ sudo gem update
$ gem list
(以下抜粋)
appengine-apis (0.0.16)
appengine-jruby-jars (0.0.7)
appengine-rack (0.0.9)
appengine-sdk (1.3.4)
appengine-tools (0.0.13)
$ appcfg.rb generate_app tdiary-appengine

これでひな形ができた。 次に Rack 対応 tDiary と DataMapper IOを持ってくる。

$ git clone http://github.com/hsbt/tdiary-core/tree/testable
$ git clone git://github.com/kdmsnr/tdiary_contrib.git

tdiary_contrib.git にある data_mapper_io.rb を tdiary-core/tdiary にコピーする。

トライ&エラー

いきなりは動かないと分かっていても、ローカルで試しながら少しずつ修正していく。

$ dev_appserver.rb .

config.ru に use ::Rack::Reloader を指定しておけば、ソースを書き換えればサーバの再起動無しに反映されるので便利。

試行錯誤の結果、修正した場所は以下の通り。

data_mapper_io.rb の修正

まず動かしたら、(Rubyではなく)JavaのNullPointerExceptionが発生してビビる。Ruby側のスタックトレースが表示されないので、場所が特定できない。 ソースのメイン処理をコメントアウトしながら、少しずつ問題箇所を特定していく。 どうやら、data_mapper_io.rb 内で、 tDiary の設定ファイルを保存している箇所で落ちているようだった。

config = DataMapper::Config.get(1)
unless config
	config = DataMapper::Config.new( :id => 1 )
	config.save  ← ここでNullPointerException発生
end

DataMapperの使い方を分かってないと先に進めなさそうだったので、appengine-jrubyのUsingTheDatastoreを見ながら小さなサンプルを作って切り分け。 その結果、 Config クラスの定義で id に Integer でなく Serial 属性を指定すれば落ちなくなることが分かった。

他にも以下の場所を修正した。

これでtdiary/data_mapper_io.rb の修正点をコミット

AppEngineの制約(スレッド生成、ファイル書き込み禁止)への対応

次に、 tDiary にて AppEngine の制約に引っかかる箇所を対応。

同じく修正点をコミット

起動スクリプトの修正

Rackの設定ファイル config.ru や、Gemライブラリの読み込みファイル (Gemfile) を AppEngine の環境に合わせて修正。 いつの間にか、 Gem ライブラリの呼び出し方法が新しくなっていたんだね。 bundler というライブラリを使うようになっているみたい。プロジェクトごとに使う gem を定義できるのが便利。

AppEngine の場合、 config.ru の読み込みが AppEngine::Rack 内で動く。 なので、以下のような指定だとうまく読み込めない。

use Rack::Reloader  # ← AppEngine::Rack::Reloader を指定したことになる

ちょっと気持ち悪いけど、以下のようにルートから指定しなくてはダメだった。

use ::Rack::Reloader

これもGitHubにコミット

まとめ

AppEngineならではの制約もあったけど、Rack対応+DataMapper対応のおかげで、比較的簡単に AppEngine でも動かすことができた。 Low Level APIを使ってAppEngine用のIOを白紙から書くのも1つの案だけど、DataMapperを使わせてもらう方が汎用的だね。

今の時点の課題