GAE HackathonでJRuby on Railsの一言掲示板つくった

GAE Hackathon Disk3詳細

Winノートには開発用のツールが何にも入ってなかったのでJavaやらgitやらなんやかやインストールするだけで持ち時間半分くらい消費して心が折れかかってたけど、最終的に作業時間が一時間追加されたこともあってなんとか動作。

ほとんどが自宅のiMacで一度やってる作業なのにこんなにセットアップに時間かかるなんて、Vista恐るべし。

http://itrain.appspot.com/

一応、JRubyで動いてる証拠として

e:Time.now

みたいにe:を頭に書けばRubyステートメントが実行されるようにしといた。ホントはThread内で$SAFE上げて実行したかったんだけど流石にThreadはGAEが使わせてくれないようなので、JRuby&GAE&みなさんを全面的に信用して

if comment_body =~ /^e:(.+)$/
  eval($1)
end

みたいなうんこ実装。問題あったら即消す。

では以下、皆さんが私の二の轍踏まないようにはまった場所を書いときます。良かったら参考にどうぞ。

時間切れ

とりあえず一番はまったのはこのエラー。

エラーメッセージには大して情報はないし、コンソールのログには何にも出ない。何かと思ってたんだけど、これ処理に時間がかかりすぎて(たぶん30秒)GAEに殺されたときに出るエラーみたい。まれに成功したりするもんで、なんなのか気づくのにえらい時間掛かった。

で、困ったときのYARBLということで、ソース見てるとappengine-web.xmlに次のような記述を発見。

<property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
<property name="jruby.compile.fastest" value="true"/>
<property name="jruby.compile.frameless" value="true"/>
<property name="jruby.compile.positionless" value="true"/>
<property name="jruby.compile.threadless" value="false"/>
<property name="jruby.compile.fastops" value="false"/>
<property name="jruby.compile.fastcase" value="false"/>
<property name="jruby.compile.chainsize" value="500"/>
<property name="jruby.compile.lazyHandles" value="false"/>
<property name="jruby.compile.peephole" value="true"/>

明らかにこの辺でパフォーマンス上がるようにJRubyのプロパティを設定してるので、とりあえず何も考えずに自分のappengine-web.xmlにコピペしたところ、一度目はほぼ確実に時間切れでエラーになるものの、とりあえずそれでメモリには乗っかってくれるようで、リロードすれば無事表示される感じに。

YARBLの人が初回の読み込みが遅いって強調してたのがよく分かった。

ログ出力

さらにその辺で例外吐いたのに伴ってログ出力周りでも「ファイルに書き込めねー」みたいなエラーが出たんだけど、これもYARBL見て解決。config/environments/production.rb

config.cache_classes = true
class ServletContextLogger
  def debug(progname = nil, &block)
    log(:DEBUG, progname, &block)
  end

  # ..snip..
  
  def log(severity, progname, &block)
    message = progname || block.call
    $servlet_context.log("#{severity}: #{message}")
  end
end
config.logger = ServletContextLogger.new

セッション

当たり前だけどGAEはActiveRecord使えないのでActiveRecord session storeも使えない。これもYARBLの人が解決してくれてる。Olabiniサイコー。lib/big_table_servlet_store.rb取って来て、config/envieronmnt.rbに以下みたいなのを追加。

require 'big_table_servlet_store'
Rails::Initializer.run do |config|
  # ..snip..
  config.action_controller.session_store = :big_table_servlet_store
end

データのCRUDとかユーザーの管理とか

こないだの日記参考にBumbleとかBeeUとか使いましょう。ちゃんと動く。

バージョン

あと最後にこれは気のせいかもしれないけど、以前の「I'm JRuby on Rails」を生かしたまま開発する為に、今回のはappengine-web.xmlでバージョンを2に設定して、2.itrain.appspot.com みたいにアクセスしてたんだけど、これだとリロードしても成功してくれなかった。

諦めてコンソールでデフォルトバージョンを2に設定して、itrain.appspot.com で確認するようにしたら改善した気がする。デフォルトに設定されてるバージョンはパフォーマンス少しよかったりするんだろうか。

まとめ

はまった点に付いては以上だけど、とりあえず身も蓋もない結論として、JRuby on Rails on GAE/Jで何か作りたいときはYARBLを落として来て、それをひな形に開発を進める」のが現時点でベストだと思う。それならはまりどころを全て回避してほぼRailsの感覚で作業できる。

フリーでRailsが動いてサーバー管理の手間もなくアクセスが増えたら勝手にスケールする。こんな環境は他にはありえないので、みんなでどんどん試してノウハウを蓄積&共有できたらうれしい。