ap4r-0.3.0 リリース

長らく時間があいてしまいましたが、新しいバージョンをリリースしました。バージョン 0.3.x では、実際のシステムで運用する際にも困らないよう足回りの強化に努めていきます。まずはデーモン・サービス化といったところですね。


とはいえ、今回の修正は非常に地味で、最新版の RubyRubyGemsRails への対応となります。あと下位互換なくなっちゃいますが、名前空間も変えました。これまでトップレベルの名前空間は ::AP4R としていましたが、ActiveSupport::CoreExtensions::String::Inflections モジュールのメソッドと相性が悪いので ::Ap4r に変えています。 ちなみに相性が悪いってのはこんな感じです。

kiwamu-imac% irb
irb(main):001:0> require 'rubygems'
=> true
irb(main):003:0> require 'active_support'
=> true
irb(main):008:0> "::AP4R".underscore
=> "/ap4_r"
irb(main):009:0> "::Ap4r".underscore
=> "/ap4r"


以下、ローカル環境で軽く触る際の手順を紹介します。
Mac ベースで書きましたが、ほかのプラットフォームでもたぶん動くと思います。WindowsRedHat なんかでも動かしてました。


■ 環境

■ 準備

  • SQLite3 のセットアップ

あとで登場する SAF機能を利用するために必要です。逆に言えば、SAFを使わないなら必要ないです。
さらっと触るだけならなくても動きます。
Windows の場合は、dllファイルをコピーするようです。詳しくは SQLite のサイトをご覧ください。

kiwamu-imac% fink install sqlite3
kiwamu-imac% (中略)
kiwamu-imac% sudo gem install sqlite3-ruby
Select which gem to install for your platform (i686-darwin8.8.1)
 1. sqlite3-ruby 1.2.1 (ruby)
 2. sqlite3-ruby 1.2.1 (mswin32)
 3. sqlite3-ruby 1.2.0 (mswin32)
 4. sqlite3-ruby 1.2.0 (ruby)
 5. Skip this gem
 6. Cancel installation
> 1
Building native extensions.  This could take a while...
Successfully installed sqlite3-ruby-1.2.1
Installing ri documentation for sqlite3-ruby-1.2.1...
Installing RDoc documentation for sqlite3-ruby-1.2.1...

AP4R のセットアップ

  • インストール

依存関係をもつ reliable-msg と uuid も一緒にインストールされるはずです。

kiwamu-imac% sudo gem install ap4r -y
  • reliable-msg へのパッチをあてる

AP4R は reliable-msg というライブラリにたいへんお世話になっていますが、gem でインストールされた reliable-msg にはバグがあります。(本家の CVS では直っています。)
なのでこれを修正しておきます。これをしとかないと設定ファイルをちゃんと読み込んでくれず、デフォルトの設定でしか動きません。

kiwamu-imac% pwd
/Users/kiwamu/gems/reliable-msg-1.1.0

対象となるファイルと行番号

lib/reliable-msg/queue-manager.rb L236
lib/reliable-msg/cli.rb L212

修正前

 drb.merge(@config.drb) if @config.drb

修正後

 drb = drb.merge(@config.drb) if @config.drb

注意:cliの方は、@config の @ が要らない


メッセージ受信時に以下のフォルダ内で uuid.state が更新されますが、あらかじめパーミションを変更しとかないとエラーになってしまいます。なので適当に変更してあげてください。Windows の場合は気にする必要ありません。

kiwamu-imac% pwd
/Users/kiwamu/gems/uuid-1.0.3

AP4R の起動
適当な名前(ここでは my_ap4r)で AP4Rホームフォルダを作成し、起動します。メッセージの永続化先としてはファイル(disk)とMySQLを選択可能ですが、今回は簡単に動かすためにファイルを利用しています。

kiwamu-imac% ap4r_setup my_ap4r
kiwamu-imac% cd my_ap4r
kiwamu-imac% ruby script/start -c config/queue_disk.cfg

■ サンプルアプリのセットアップ

  • 取得
kiwamu-imac% curl -O http://rubyforge-files.ruby-forum.com/ap4r/HelloWorld-0.3.0.tar.gz

あるいは、RubyForge のサイトから直接 DL してください。

http://rubyforge.org/frs/?group_id=1765

  • 展開
kiwamu-imac% tar xvfz HelloWorld.tar.gz
kiwamu-imac% cd HelloWorld
  • SAF機能で利用するテーブルを作成

最初の準備の SQLite3 と同様、SAF機能を利用せずに動かすのであれば、このステップは不要です。

kiwamu-imac% rake db:migrate
/usr/local/bin/rake:17:Warning: require_gem is obsolete.  Use gem instead.
(in /Users/kiwamu/work/svn/ap4r/trunk/samples/HelloWorld-0_3_x)
== CreateTableForSaf: migrating ===============================================
-- create_table(:stored_messages)
   -> 0.1795s
== CreateTableForSaf: migrated (0.1797s) ======================================
  • サンプルアプリの起動
kiwamu-imac% ruby script/server

■ サンプルアプリを実行する
以下のURLをたたくことで、実行されます。
サンプルの内容は、2つの連続する処理を実行しているするだけです。最初の処理A は "Hello" とファイルに書き出します。次の処理B は 10秒待ったあと "World" とファイルに書き出します。後者が重たい処理のイメージですね。

処理A → 処理B を同期的に処理しなければならない場合は、クライアントに実行結果が返るまでに10秒以上かかります。しかし、処理Bを非同期として処理可能であれば、瞬く間に結果が返ってきます。粗結合化によるレスポンス向上の非常に単純な一例ですね。
アプリ画面の見た目上、動きがわかりにくいのが難点ですが...そのうち直します。 (^^; 


処理Aは AP4Rに後続処理をよろしく〜というメッセージを渡してクライアントに結果を返します。一方、AP4R は受け取ったメッセージを 再度 Rails に投げつけて処理B を実行してもらいます。この投げつける際のプロトコルがいくつかあり、それぞれ次の URL をたたくことで変わるようなサンプルにしています。

また、ずっと説明を先延ばしにしてきたSAF機能も次の URL をたたくことで試せます。

ちなみに、SAF機能については以前のエントリでも触れていますが、はしょって説明すると

  • Store and forward の略
  • いったん Store したのち、forward することで以下の2つを保証
    • 前処理がエラーになった場合は、後処理はけっして実行しない
    • 前処理が正常だった場合には、後処理のためのメッセージが残る
  • もう少し説明すると、
    • なんらかの業務処理のあとに AP4R にメッセージを投げると、業務DB へのコミットと ap4r へのコミットを1トランザクションにしないとメッセージの配送が保証されない
    • でもこれってけっこう大変...
    • なので、SAF
    • 業務DB に SAF 用のテーブルを作成しておき、業務DBへのコミット時に AP4R に投げる予定のメッセージを永続化(store)しておく
    • 業務DBへのコミットが正常に済んだタイミングで、SAFテーブルに格納されていたメッセージを ap4r に配送(forward)
    • こうしておけば、N/Wの瞬断やDBサーバダウンの影響で、業務DBはロールバックされてしまったときには SAFテーブルもロールバックされるので、後処理がはしることもないし、
    • 正常終了した場合は、SAF テーブルにメッセージが残ることになる
  • kiwamu日記 - SAF(Store and forward)機能について

http://d.hatena.ne.jp/kiwamu/20061013/1161017209

実際にメッセージが残ってるかを確認してみると、こんな感じになります。

kiwamu-imac% ruby script/console
Loading development environment.
>> y ::Ap4r::StoredMessage.find(:all)
--- 
- !ruby/object:Ap4r::StoredMessage 
  attributes: 
    status: "1"
    updated_at: 2007-04-06 18:16:46
    duplication_check_id: 771256f0-c64d-0129-cea6-0016cb9ad524
    id: "1"
    queue: queue.async_world.execute
    object: "\x04\b{\a:\rworld_idi\x06:\fmessage\"\n\
      World"
    headers: "\x04\b{\t:\x12dispatch_mode:\vXMLRPC:\rdelivery:\tonce
             :\x12target_action\"\fExecute
             :\x0Ftarget_url\"*http://localhost:3000/async_world/api"
    created_at: 2007-04-06 18:16:45
=> nil
>>

なんだか妙に長くなってしまいましたが、難しいことはとくにしてないと思います。
非同期で呼ぶ処理も Rails上のただのアクションなので、既存のアプリを簡単に非同期化できるあたりが嬉しいかなぁと思います。もちろん、(非同期で行う処理の)順序保障がないので、それでも問題ない処理、あるいは設計になっていることが前提ですが...。 (^^;


よかったら動かしてみてやってください。