JRuby上で動かしてみました

GW 明けの JavaOne では、JRuby 1.0 のリリースが期待されています。
JRuby 上で AP4R を動かせれば、枯れた VM 上で動くという安心感もあるし、既存の Javaアプリとの連携もちょっと楽になるかもなぁと妄想しつつ、、、
今回は Ruby本家の処理系で動く Rails アプリと JRuby 上で動く AP4R を連携させてみました。

  • 準備

まずは、JRuby 本体をインストールします。

% curl -o http://dist.codehaus.org/jruby/jruby-bin-0.9.8.tar.gz
% tar xvf jruby-bin-0.9.8.tar.gz
% mv jruby-bin-0.9.8 jruby-0.9.8
% mv jruby-0.9.8 /usr/local


環境変数を設定しておきます。

% export JRUBY_HOME=/usr/local/jruby-0.9.8
% export PATH=$PATH:$JRUBY_HOME/bin


続いてJRuby用にRubyGemsをインストールします。

% curl -O http://files.rubyforge.vm.bytemarkco.uk/rubygems-0.9.2.tgz
% tar xvfz rubygems-0.9.2.tgz
% cd rubygems-0.9.2.tgz
% jruby setup.rb
  • AP4R のセットアップ

いつもと同じように、gem からインストールします。

% sudo /usr/local/jruby-bin-0.9.8/lib/ruby/gem install ap4r -y


AP4R の作業フォルダをつくります。

% cd ~/work/temp
% /usr/local/jruby-0.9.8/bin/ap4r_setup my_ap4r
make application root directory [/Users/kiwamu/work/temp/my_ap4r] ... 
make directories for AP4R [config, log, script, tmp] ...
copy files from /usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/ap4r-0.3.0/config to /Users/kiwamu/work/temp/my_ap4r/config ...
copy files from /usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/ap4r-0.3.0/script to /Users/kiwamu/work/temp/my_ap4r/script ...

[/Users/kiwamu/work/temp/my_ap4r] has successfully set up!


で、起動します。ここまで非常に順調でした♪

% cd my_ap4r
% jruby script/start -c config/queues_disk.cfg
Loaded queues configuration from: /Users/kiwamu/work/temp/my_ap4r/config/queues_disk.cfg
Using message store: disk
Error in starting queue-manager undefined method `sysseek' for #<File:/Users/kiwamu/work/temp/my_ap4r/queues/master.idx>
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/message-store.rb:356:in `method_missing'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/message-store.rb:356:in `update'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/message-store.rb:278:in `synchronize'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/message-store.rb:369:in `update'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/message-store.rb:278:in `activate'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/queue-manager.rb:233:in `start'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/ap4r-0.3.0/lib/ap4r/script/../../ap4r/queue_manager_ext.rb:59:in `synchronize'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/queue-manager.rb:269:in `start'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/ap4r-0.3.0/lib/ap4r/script/../../ap4r/queue_manager_ext.rb:59:in `start'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/cli.rb:109:in `synchronize'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/ap4r-0.3.0/lib/ap4r/script/../../ap4r/queue_manager_ext.rb:63:in `start'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/reliable-msg-1.1.0/lib/reliable-msg/cli.rb:109:in `run'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/ap4r-0.3.0/lib/ap4r/script/../../ap4r/script/queue_manager_control.rb:23:in `run_rm_client'
/usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/ap4r-0.3.0/lib/ap4r/script/../../ap4r/script/queue_manager_control.rb:13:in `start'
script/start:5


あ... orz

  • 原因追及

エラー文言をみると、どうも IO#sysseek なんていうメソッドはないと怒られているっぽい。よくよく見てみると、JRuby では、sysread や syswrite はあるのに sysseek の実装がない...

% cat hoge >> hoge
% jirb
irb(main):001:0> f=File.new("hoge")
=> #<File:hoge>
irb(main):002:0> f.sysseek(1, IO::SEEK_SET)
NoMethodError: undefined method `sysseek' for #<File:hoge>
        from (irb):1:in `method_missing'
        from (irb):1:in `binding'
irb(main):003:0> f.methods.any? {|m| m == "sysseek"}
=> false
irb(main):004:0> f.methods.any? {|m| m == "seek"}   
=> true


IO#seek はあるので、違いを見てみると戻り値だけらしい。

  • ios.sysseek(offset, whence=SEEK_SET) => integer

Seeks to a given offset in the stream according to the value of whence (see IO#seek for values of whence). Returns the new offset into the file.

f = File.new("testfile")
f.sysseek(-13, IO::SEEK_END) #=> 53
f.sysread(10) #=> "And so on."

  • ios.seek(amount, whence=SEEK_SET) → 0

Seeks to a given offset anInteger in the stream according to the value of whence:


IO#sysseek を呼び出しているのは reliable-msg/message-store.rb ですが、とくに戻り値を利用しているわけではなかったので、このメソッドをすべて IO::seek に置き換えてみます。


あ、あと忘れずに gems 以下の uuid-x.x.x の permission も変えておきます。

% sudo chmod 757 /usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/uuid-1.0.3
  • リトライ

気を取り直して、AP4R を再び起動してみます。

% sudo chmod 757 /usr/local/jruby-0.9.8/lib/ruby/gems/1.8/gems/uuid-1.0.3
% Rm -rf queues/master.idx
% jruby script/start -c config/queues_disk.cfg
Loaded queues configuration from: /Users/kiwamu/work/temp/my_ap4r/config/queues_disk.cfg
Using message store: disk
Accepting requests at: druby://localhost:6438
about to start dispatchers with config --- 
- threads: 1
  targets: queue.*

dispatch targets are : queue.*;
start dispatcher: targets= #<ReliableMsg::MultiQueue:0xc89df9> (index 0)
queue manager has forked dispatchers


今度はうまくいったようです♪


  • サンプルアプリを実行

こちらは Ruby でふつーに実行しておきます。

% cd ~/work/temp
% curl -O http://rubyforge-files.ruby-forum.com/ap4r/HelloWorld-0.3.0.tar.gz
% tar xvfz HelloWorld-0.3.0.tar.gz
% cd HelloWorld
% ruby script/server


ブラウザから以下の URL をたたいてみてください。

http://localhost:3000/sync_hello/execute_via_http

ちゃんと動いたでしょうか? JRuby、素晴らしいですね〜♪

JRuby上で動かした Railsアプリとの連携はまだちょっとうまくいかなかったので、そこらへんはまた後日... (^^;