AP4R,Rubyで非同期メッセージング

第2回 AP4RとRailsでつくる非同期アプリケーション

この記事を読むのに必要な時間:およそ 12 分

非同期アプリケーションへの拡張

非同期化の方針のおさらい

決済処理を注文処理から分離します。注文処理と決済処理の疎結合化です。時間のかかっていた決済処理を実行することなく応答を返すことができるようになるので,お客さんのイライラ解消につながるでしょう。また,他社のシステムと連携した決済処理は,これまで他社のシステムメンテナンスや障害に影響されていましたが,今後はそのような場合でも注文を受け付けることが可能になります。

非同期化のAPI

非同期メッセージ送信のAPIは,Railsプラグインで提供されるヘルパーメソッドを使います。

ap4r.async_to({...},   # 次の処理を指定するオプション
              {...})   # リクエストするデータ

ap4r が,AP4Rのプラグインで提供されるメソッドです。 async_to メソッドには,引数として,非同期処理として実行されるアクションの指定,及びパラメータを渡します。アクションの指定は,Railsの url_for と同様に指定するか, :url キーにURLを指定することが出来ます。URLを直接指定することで,Railsではないサービスにも非同期処理を行わせることができます。

いざ,コード拡張

今回の同期アプリケーションの場合,変更箇所はasync_shop_controller.rbの order アクションと payment アクションになります。以下に修正前のものと修正後のものを並べます。

修正前
class AsyncShopController < ApplicationController
  (省略)

  def order
    begin
      Order.transaction do
        @order = Order.new(params[:order])
        @order.save!
        payment(@order[:id])                     # ...(1)

        flash[:notice] = 'Order was successfully created.'
        redirect_to :action => 'index'
      end
    rescue Exception
      flash[:notice] = 'Order was failed.'
      render :action => 'order_form'
    end
  end

  private
  def payment(order_id)
    sleep 5

    payment = Payment.new
    payment.order_id = order_id                  # ...(2)
    payment.save!
  end
  
  (省略)
end
修正後
class AsyncShopController < ApplicationController
  (省略)

  def order
    begin
      Order.transaction do
        @order = Order.new(params[:order])
        @order.save

        ap4r.async_to({:action => 'payment'},
                      {:order_id => @order.id})  # ...(3)

        flash[:notice] = 'Order was successfully created.'
        redirect_to :action => 'index'
      end
    rescue Exception
      flash[:notice] = 'Order was failed.'
      render :action => 'order_form'
    end
  end

  def payment
    sleep 5 

    payment = Payment.new
    payment.order_id = params[:order_id]         # ...(4)
    payment.save
    render :text => "true"                       # ...(5)
  end
  
  (省略)
end

いかがでしょう?

修正前後であまり大きな違いはないように見えるのではないでしょうか。変更箇所を順に見ていきます。

修正前に payment アクション(メソッド)を呼び出していた部分(1)が非同期化にともなってなくなり,代わりに ap4r.async_to メソッド(3)となります。次の処理として同じコントローラ内の payment アクションを指定し, @order.id をリクエストデータとして渡しています。非同期メッセージ送信する側の変更は以上で終了です。

次に非同期として処理される側, payment アクション(privateメソッドからアクションに変わっています)をみてみましょう。修正前は @order.id を引き数として受け取り, payment にセット(2)していました。修正後にはこの引き数がなくなっています。リクエストデータとして渡されたものは,画面から渡るデータと同様に params でアクセス可能なので,⁠4)のようにして payment にセットしています。キーは,⁠3)で指定していたものとなります。

最後に,非同期処理が問題なく終了したことをAP4Rサービスに伝えるために(5)の記述が必要になります。

非同期アプリケーションの一連のコードはこちらから取得できます。

% svn checkout http://ap4r.rubyforge.org/svn/tags/200709_gihyo_async_shop

実行

Railsプロセスを起動します。

% cd as_rails
% ruby script/server

AP4Rプロセスを起動します。

% cd as_ap4r
% ruby script/mongrel_ap4r start -A config/queues_mysql.cfg

画面から注文処理を実行します。

「Order」ボタンを押すとすぐに注文結果のリストが表示されるでしょう。決済日時(Payed_at)は"not yet."となっています。非同期アプリケーションに拡張した結果,注文情報の保存処理が実行されるとすぐにユーザーに応答が返るようになりました。⁠重い」決済処理はユーザーの知らぬ間に実行されているはずです。画面をリロードすると,決済日時の表示が変わり,決済処理が無事に終了したことを確認できると思います。

図4 非同期アプリケーションの実行結果

図4 非同期アプリケーションの実行結果

著者プロフィール

加藤究(かとうきわむ)

フューチャーアーキテクト株式会社,シニアコンサルタント。土木専攻だった大学時代には,道路や橋の建設について学んできたが,社会に出てからは Javaのメッセージングミドルウェアの開発/保守などに従事。昨年,Rubyで書いたメッセージングライブラリ,AP4Rでオーンソースの世界に仲間入り。現在は,AP4Rの開発/導入サポート中。

URLhttp://d.hatena.ne.jp/kiwamu/


篠原俊一(しのはらしゅんいち)

フューチャーアーキテクト株式会社,シニアコンサルタント。大学時代は物理学を専攻,素粒子論を研究,10次元の世界に住んでいた。入社後まもなく,Martin FowlerのblikiでRubyを知り,"The Ruby Way"に学ぶ。 Rubyとオープンソースが大好きなプログラマとして,AP4Rを開発中。

URLhttp://d.hatena.ne.jp/ita-wasa/