HellWorldサンプル
ap4r-0.2.0をリリースしました。
- [ANN] ap4r-0.2.0 Released
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/220383
前回のエントリでも触れていますが、新しいバージョンで追加された機能は、
- 非同期連携プロトコルの拡充
- SAF(Store and forward)による信頼性の向上
となります。今回はこれらの機能が実際にどのように使われるのかをサンプルを通じて紹介したいと思います。サンプルはgem同様、RubyForgeにて公開しています。DLはこちらから。
HelloWorldサンプルは単純なファイル書き出しアプリ(書き出す文字が"HelloWorld")で、同期処理(SyncHelloControllerの各アクション)と非同期処理(AsyncWorldControllerの各アクション)で構成されています。基本的な処理の流れは、以下のとおりです。
- Rails上での同期処理
- クライアントからのアクション呼び出し
- ファイル書き出し
- キュー(reliable-msg)に後続処理のためのメッセージを突っ込む
- Rails上での非同期処理
- アクション呼び出し
- (sleep 10)
- ファイル書き出し
AP4Rからの後続処理の呼び出しプロトコルによって同期処理部分のアクションは以下のようになります。いずれも後続処理用のパラメータを作成し、async_dispatchメソッドに渡します(このメソッドのなかでキューへの突っ込みが行われます)。
def execute open( 'HelloWorld.txt', 'w' ) do |f| f.puts "Hello # ...written at #{Time.now.to_s}"; end req = WorldRequest.new(:world_id => 1, :message => "World") async_dispatch(req, {:controller => 'async_world', :action => 'execute'}, {:dispatch_mode => :XMLRPC} ) render :action => 'response' end
def execute_via_soap open( 'HelloWorld.txt', 'w' ) do |f| f.puts "Hello # ...written at #{Time.now.to_s}"; end req = WorldRequest.new(:world_id => 1, :message => "World") async_dispatch(req, {:controller => 'async_world', :action => 'execute'}, {:dispatch_mode => :SOAP} ) render :action => 'response' end
- HTTP
def execute_via_http open( 'HelloWorld.txt', 'w' ) do |f| f.puts "Hello # ...written at #{Time.now.to_s}"; end req = {:world_id => rand(100), :message => "World"} async_dispatch(req, {:controller => 'async_world', :action => 'execute_via_http'}, {:dispatch_mode => :HTTP} ) render :action => 'response' end
どのプロトコルでもだいたい似たような実装となるようにしています。注意する点としては、XML-RPCやSOAPを利用した場合にはパラメータとしてActionWebService::Structを継承したクラスが必要になり、またサービスのスケルトンクラスが必要になることです。
サンプルではそれぞれ以下のようなクラスがあります。
class WorldRequest < ActionWebService::Struct member :world_id, :int member :message, :string end
class AsyncWorldApi < ActionWebService::API::Base api_method :execute, :expects => [{:request => WorldRequest}], :returns => [:bool] end
生のHTTPを利用した場合には、こうしたクラスは必要ないのでアプリケーションの開発者としては同期/非同期処理の連携時にとくに気を遣う必要がなくなります♪
ちなみにSAFを利用する場合には、上記処理をtransaction_with_safメソッドのブロックに書くだけになります。こうすると、async_dispatchメソッドの中でsotreし、ブロックを抜けたところでforward(実際にキューに突っ込む)するようになります。
シンプルだな〜と感じてもらえるとよいのですが... (^^;
- SAFを利用(at-least-once なQoSレベルとなりメッセージをロストしません)
def execute_with_saf @delete_mode = :logical # another option is :physical. transaction_with_saf do open( 'HelloWorld.txt', 'w' ) do |f| f.puts "Hello # ...written at #{Time.now.to_s}"; end req = WorldRequest.new(:world_id => 1, :message => "World") async_dispatch(req, {:controller => 'async_world', :action => 'execute'}, {:dispatch_mode => :XMLRPC} ) render :action => 'response' end end
興味が湧いたらぜひ触ってみてください! よろしくお願いします。