reliable-msg を Ruby 1.9 系でも動くようにする
やりたいこと
タイトルの通り
reliable-msg を Ruby 1.9 系でも動くようにしたい
git でソースを作者様リポジトリから取ってくる
[hamajyotan@host ~]$ git clone https://github.com/assaf/reliable-msg.git Cloning into reliable-msg... remote: Counting objects: 129, done. remote: Compressing objects: 100% (63/63), done. remote: Total 129 (delta 67), reused 121 (delta 63) Receiving objects: 100% (129/129), 45.14 KiB, done. Resolving deltas: 100% (67/67), done. [hamajyotan@host ~]$
とりあえず Ruby 1.9 環境で rake テスト
[hamajyotan@host ~]$ cd reliable-msg [hamajyotan@host reliable-msg]$ ruby -v ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux] [hamajyotan@host reliable-msg]$ rake (in /home/sakaguchi/reliable-msg) /usr/local/bin/ruby -w -I"lib" "/usr/local/lib/ruby/1.9.1/rake/rake_test_loader.rb" "test/test-rails.rb" "test/test-queue.rb" "test/test-topic.rb" /home/sakaguchi/reliable-msg/lib/reliable-msg/queue.rb: /home/sakaguchi/reliable-msg/lib/reliable-msg/queue.rb:332: Invalid retry (SyntaxError) rake aborted! Command failed with status (1): [/usr/local/bin/ruby -w -I"lib" "/usr/local...] /usr/local/lib/ruby/1.9.1/rake.rb:993:in `block in sh' /usr/local/lib/ruby/1.9.1/rake.rb:1008:in `call' /usr/local/lib/ruby/1.9.1/rake.rb:1008:in `sh' # # 途中省略。。 # /usr/local/lib/ruby/1.9.1/rake.rb:2013:in `top_level' /usr/local/lib/ruby/1.9.1/rake.rb:1992:in `run' /usr/local/bin/rake:31:in `<main>' [hamajyotan@host reliable-msg]$
構文エラーのようだ。
色々改修していく
lib/reliable-msg/queue.rb 332行目
retry が使われている
def next selector, &block load = false @mutex.synchronize do load ||= (@list.nil? || @list.empty?) @list = block.call() if load @list.each_with_index do |headers, idx| if selector.match headers @list.delete_at idx return headers[:id] end end unless load load = true retry end end return nil end
これは Ruby 1.9 ではダメ、代わりに redo を使いたいところ
#next メソッドが実行されている箇所を確認する
lib/reliable-msg/queue.rb 249行目 付近
# Validate the selector: nil, string or hash. selector = case selector when String {:id=>selector} when Hash, Selector, nil selector else raise ArgumentError, ERROR_INVALID_SELECTOR end # If using selector object, obtain a list of all message headers # for the queue (shared by all Queue/Selector objects accessing # the same queue) and run the selector on that list. Pick one # message and switch to an :id selector to retrieve it. if selector.is_a?(Selector) cached = @@headers_cache[@queue] ||= CachedHeaders.new id = cached.next(selector) do if tx tx[:qm].list :queue=>@queue, :tid=>tx[:tid] else repeated { |qm| qm.list :queue=>@queue } end end return nil unless id selector = {:id=>id} end
#next メソッドを呼んでいるレシーバの cached 更に、引数の selector
これらは共に変数なので再評価されても副作用はない。
よって、 retry をそのまま redo に変更しても問題なさそう。
参考 ⇒ http://d.hatena.ne.jp/hamajyotan/20110410/1302409054
lib/reliable-msg/client.rb 92行目と100行目
Selector.new &block
これは
Selector.new(&block)
こうする。
lib/reliable-msg/selector.rb 70行目
メタプログラミング Ruby 曰く、ブランクスレートしてるコード
instance_methods.each { |name| undef_method name unless name =~ /^(__.*__)|instance_eval$/ }
object_id を undef しちゃダメとの警告、故に例外に加える
instance_methods.each { |name| undef_method name unless name =~ /^(__.*__)|instance_eval|object_id$/ }
test/test-queue.rb 123, 131, 146, 160 行目
begin @queue.get do |msg| assert msg && msg.id == id1, "Block called without the message" raise AbortTransaction end flunk "Message not found in queue, or exception not propagated" rescue AbortTransaction end
ブロック外の変数 msg がブロック引数 msg とかぶっている
begin @queue.get do |m| assert m && m.id == id1, "Block called without the message" raise AbortTransaction end flunk "Message not found in queue, or exception not propagated" rescue AbortTransaction end
lib/reliable-msg/cli.rb 197行目
else raise InvalidUsage end rescue InvalidUsage puts USAGE end end
インデントがズレているゆえの警告
else raise InvalidUsage end rescue InvalidUsage puts USAGE end end
test/test-queue.rb 29行目
require 'lib/reliable-msg'
require できないので修正、他のテストスクリプトと合わせる。
require 'reliable-msg'
lib/queue-manager.rb 187, 191, 194行目
return if @@active == self Thread.critical = true if @@active.nil? @@active = self else Thread.critical = false raise RuntimeError, ERROR_QM_STARTED end Thread.critical = false
Thread.critical は無くなった
return if @@active == self # Thread.critical = true if @@active.nil? @@active = self else # Thread.critical = false raise RuntimeError, ERROR_QM_STARTED end # Thread.critical = false
lib/reliable-msg/queue.rb 70行目あたり
def initialize(queue = nil, options = nil) @priority, @expires, @max_deliveries, @delivery = nil # 追加
初期化されないインスタンス変数の参照警告に対する対応
端折るが、同警告の対応をちらほらと。
ハマりポイント
ブロック引数とブロック外引数が同名である場合の挙動
Ruby 1.8 系
irb(main):001:0> RUBY_VERSION => "1.8.6" irb(main):002:0> x = 5 => 5 irb(main):003:0> [1, 2, 3].each { |x| irb(main):004:1* puts x irb(main):005:1> } 1 2 3 => [1, 2, 3] irb(main):006:0> x => 3
Ruby 1.9 系
irb(main):001:0> RUBY_VERSION => "1.9.2" irb(main):002:0> x = 5 => 5 irb(main):003:0> [1, 2, 3].each { |x| irb(main):004:1* puts x irb(main):005:1> } 1 2 3 => [1, 2, 3] irb(main):006:0> x => 5
Ruby 1.8 系では、外側の引数へ影響を与え、 Ruby 1.9 系では、外側の引数はシャドーされる。
ReliableMsg で1箇所、 Ruby 1.8 系の挙動を期待するコードがあった。
改修後、 Ruby 1.9 系でテスト実行
[hamajyotan@host reliable-msg]$ ruby -v ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux] [hamajyotan@host reliable-msg]$ rake (in /home/sakaguchi/reliable-msg) /usr/local/bin/ruby -w -I"lib" "/usr/local/lib/ruby/1.9.1/rake/rake_test_loader.rb" "test/test-rails.rb" "test/test-queue.rb" "test/test-topic.rb" Loaded suite /usr/local/lib/ruby/1.9.1/rake/rake_test_loader Started I, [2011-04-18T01:16:06.721649 #12139] INFO -- : Loaded queues configuration from: /home/sakaguchi/reliable-msg/queues.cfg I, [2011-04-18T01:16:06.721784 #12139] INFO -- : Using message store: disk I, [2011-04-18T01:16:06.723568 #12139] INFO -- : Accepting requests at: druby://localhost:6438 # # 途中省略。。 # I, [2011-04-18T01:16:25.856555 #12139] INFO -- : Stopped queue manager at: druby://localhost:6438 I, [2011-04-18T01:16:25.856668 #12139] INFO -- : Using message store: disk I, [2011-04-18T01:16:25.857284 #12139] INFO -- : Accepting requests at: druby://localhost:6438 I, [2011-04-18T01:16:25.857772 #12139] INFO -- : Stopped queue manager at: druby://localhost:6438 . Finished in 19.137064 seconds. 11 tests, 97 assertions, 0 failures, 0 errors, 0 skips Test run options: --seed 37415 [hamajyotan@host reliable-msg]$
すべてテストをパスした!!更に警告無し!!
gem 化して確認
gem 化
[hamajyotan@host reliable-msg]$ gem build reliable-msg.gemspec WARNING: bin/queues is missing #! line Successfully built RubyGem Name: reliable-msg Version: 1.2.0 File: reliable-msg-1.2.0.gem
インストール
[hamajyotan@host reliable-msg]$ sudo gem install reliable-msg-1.2.0.gem Successfully installed reliable-msg-1.2.0 1 gem installed
キューマネージャ起動、終了
[hamajyotan@host reliable-msg]$ queues manager start I, [2011-04-18T01:19:04.841320 #12398] INFO -- : Loaded queues configuration from: /home/sakaguchi/reliable-msg/queues.cfg I, [2011-04-18T01:19:04.841743 #12398] INFO -- : Using message store: disk I, [2011-04-18T01:19:04.845010 #12398] INFO -- : Accepting requests at: druby://localhost:6438 # ここで Ctrl+C ^CI, [2011-04-18T01:19:06.555624 #12398] INFO -- : Stopped queue manager at: druby://localhost:6438 [hamajyotan@host reliable-msg]$
動いた!!
とりあえず
fork して作業成果を配置。
https://github.com/hamajyotan/reliable-msg