EIP / Event-Driven Consumer


Event-Driven Consumer

一言要約

Event-Driven Consumerを利用することで、リソースの無駄遣いをさせずにメッセージの処理を行うことができる。


Problem

メッセージが利用可能となると自動的にアプリケーションがメッセージを使用できるようにするにはどうすればいいか?

Detail

アプリケーションは、メッセージが届くとすぐにMessageを使用することを必要とする。 Polling Consumersでの問題は、チャンネルが空のときに、コンシューマがスレッドをブロックし、もしくは/かつ、ここにはないメッセージのためにポーリングしている間、処理時間を消費してしまうことである。


ポーリングは、クライアントが消費率を制御できるようする、しかし消費するものが何もないときリソースを無駄使いしてしまう。 消費するメッセージがあるかどうかを継続的にチャンネルに問い合わせるよりはむしろ、もしメッセージが到着したときにチャンネルがクライアントに教えることができればよいだろう。そういうことであれば、コンシューマがメッセージのために投票する代わりに、メッセージが利用可能になったらすぐにコンシューマにメッセージを付与する。


アプリケーションは、Event-Driven Consumerを使うべきである。Event-Driven Consumerは、メッセージがチャンネルで配信されたときに自動的にメッセージを扱う。


これもまた非同期のレシーバーとして知られている。レシーバーは、コールバックスレッドがメッセージを配信するまで実行中のスレッドがない。私達は、それをEvent-Driven Consumerと呼ぶ。レシーバーは、メッセージ配信が動作中のレシーバーをトリガーとするイベントで動作するするからである。


Event-Driven Consuerは、メッセージがコンシューマのチャンネルに到着した時にメッセージングシステムによって起動するオブジェクトである。コンシューマはアプリケーションのAPIでコールバックを通じて、メッセージをアプリケーションに渡す。(どうやってメッセージングシステムが、メッセージが特定の実装であり、イベント駆動になるかもしれないかどうかを、取得しているのか。すべてのコンシューマが、メッセージングシステムがメッセージを通過することで起動させるまで、アクティブなスレッドがない停止状態にすることができること、を知っている。)


Event-Driven Consumerは、メッセージシステムによって起動されるにもかかわらず、Event-Driven Consumerはアプリケーション特有のコールバックを起動する。このギャップを埋めるために、コンシューマは、メッセージングシステムで定義されたよく知られているAPIに確認をとるアプリケーション特有の実装がされている。



Event-Driven Consumerのためのコードは、2つのパートからなる。

1.Initialization(初期化)

アプリケーションは、アプリケーション特有のコンシューマを生成し、特定のMessage Channelと結びつける。このコードが一度実行した後に、コンシューマは一連のメッセージを受信する準備が整う。


2.Consumption(消費)

コンシューマは、メッセージを受信し、アプリケーションへ処理するために渡す。このコードは、メッセージが消費する度に一度実行する。

※msのメッセージグシステムからシーケンス図抜粋してきました.

http://msdn.microsoft.com/en-us/library/aa480027.aspx:Messaging Patterns in Service-Oriented Architecture, Part 1


アプリケーションは、カスタムコンシューマを生成し、チャンネルと結びつける。いったん、コンシューマが初期化されると、その時に、スレッドが実行されていない、メッセージが到着した時に起動するのを待っている、活動休止状態にできる。


メッセージが配信されたとき、メッセージッシうテムはコンシューマのメッセージ受信イベントのメソッドを呼び出し、パラメータとしてメッセージを渡す。コンシューマは、アプリケーションにメッセージを渡し、アプリケーションのコールバックAPIを利用する。アプリケーションは、今や、メッセージを持っていて処理することができるようになる。一度アプリケーションがメッセージを処理することが完了すると、次のメッセージがくるまでコンシューマは、もう1度、その時点で活動休止状態にすることができる。典型的に、メッセージングシステムが、1つのコンシューマを通じて、複数のスレッドで動いていないので、コンシューマは1度に1つのメッセージだけを処理することができる。


他のパターンとの関連

Event-Driven Consumerは、自動的に利用可能になったメッセージを消費する。

  • 消費率の制御をよりきめ細かくするためには、Polling Consumerを利用する。
  • Event-Driven Consumerは、Competing Consumersになることができる。
  • Event-Driven Consumerは、Selective Consumerになることができる。
  • Event-Driven Consumerは、Durable Subscriberにもなることができる。
  • Message Dispatcherは、Event-Driven Consumerとして実装させることができる。
  • Transactional Clientsは、Pooling Consumersで動かしているときに、Event-Driven Consumerと一緒だと同じように動作しないだろう。

Example: JMS Message Listener

JMS では、Event-Driven ConsumerMessageListener?インターフェイスを実装しているクラスとなる。 このインターフェイスは、1つのメソッド(onMessage(Message) ) が定義されている。 コンシューマは、メッセージを処理するために、onMessageを実装している。 ここでは、JMS performerの例を取り上げる。


Event-Driven Consumerの初期化部分は、要求されたperformer object を生成する、そして、要求されたチャンネルためにメッセージコンシューマと関連付ける。


今、メッセージは目的地に配信される、JMSプロバイダーはMyEventDrivenConsumer?.onMessageを、パラメータとしてメッセージと一緒に呼び出す。


Transactional ClientでもあるEvent-Driven Consumerは、予期した動作をしないだろう。一般的に、トランザクション内のコードが例外を投げるとき、トランザクションはロールバックする。しかし、MessageListener?.onMessage の特性は、投げられた例外のために提供しない。そして、ランタイム例外はプログラマーがエラーを検討する。もしランタイム例外が発生したら、JMSプロバイダーは次のメッセージが配信されることで応答する。それで、例外を引き起こしたメッセージは失われる。 トランザクションが無事に成功させるためには、イベント駆動に振る舞う、message-driven EJBを利用する。

Example: .NET RecieveCompetedEventHandler?

.NETでは、Event-Driven Consumer の performer 部分は、ReceiveCompletedEventHandler? delegate であるメソッドに実装されている。 このdelegateメソッドは、2つのパラメータを受け取らなければならない。 MesssageQueue? のオブジェクトと、ReceiveCompleted? イベントからの引数であるReceveCompletedEventArgs?。メソッドは、メッセージをキューから取得し、処理するために、引数を使用する。ここでは、NET performaerの例をあげる。


Event-Driven Consumer のクライアントの初期化部分は、ReceiveCompletd?キューはdelegateメソッドを実行すべきである、キューを特定する。

担当者のつぶやき

JMS1.1とHapnerについてのリンク掲載しておきます。


みんなの突っ込み