このエントリは2019/06/28現在の情報に基づきます。今後の機能追加や廃止に伴い、記載内容との齟齬が発生する可能性があります。
Azure Service Busとは
Microsoft Azure Service Bus は、フル マネージド エンタープライズ統合メッセージ ブローカーです。 Service Bus の最も一般的な用途は、アプリとサービスを相互に分離する場合です。Service Bus は非同期データと状態転送に適した信頼性の高い安全なプラットフォームです。 データは、メッセージを使用してさまざまなアプリとサービス間で転送されます。 メッセージはバイナリ形式であり、JSON、XML、または単なるテキストを含むことができます。
Azure Service Bus とは
https://docs.microsoft.com/azure/service-bus-messaging/service-bus-messaging-overview
上記の通り、メッセージブローカーで、オンプレミスでいうところのWebSphere MQやRabbit MQ、JMS実装などに類するもの。名前だけだと、SOA的なService Busと勘違いするが違うので要注意。
他サービスが提供するQueue/Topicとの違い
詳細は以下のドキュメントを参照。
Storage キューと Service Bus キューの比較 / Storage queues and Service Bus queues – compared and contrasted
https://docs.microsoft.com/azure/service-bus-messaging/service-bus-azure-and-service-bus-queues-compared-contrasted
Azure メッセージング サービスの中から選択する – Azure Event Grid、Event Hubs、および Service Bus / Choose between Azure messaging services – Event Grid, Event Hubs, and Service Bus
https://docs.microsoft.com/azure/event-grid/compare-messaging-services
もしくは、以下のエントリを参照。
Queue/Topicが使えるサービス
https://logico-jp.io/2019/06/11/how-to-choose-queue-or-topic-services/
データの出し入れ
データを入れる場合
サポートされている Service Bus API クライアントを使用した Service Bus への送信操作では、通常、明示的に解決されます。API 操作は、Service Bus からの受信結果を受け取るまで待機してから送信操作を完了します。
送信操作の解決 / Settling send operations
Service Bus によってメッセージが拒否された場合、拒否には、”追跡 ID” が含まれたテキストとエラーのインジケーターが含まれます。 拒否には、操作が成功する可能性があり、操作を再試行するかどうかに関する情報も含まれています。 この情報はクライアント内で例外に変換され、送信操作の呼び出し元に報告されます。 メッセージが受け取られた場合、操作は自動的に完了します。
https://docs.microsoft.com/azure/service-bus-messaging/message-transfers-locks-settlement#settling-send-operations
ドキュメント上、送信して結果を受け取るところまで待機する方式で実装することが推奨されている。Fire-forget形式を選択することも可能ではあるが、データのロストが発生する可能性があることは認識しておく必要がある。
データを出す場合
PeekLock
受信クライアントが、受信したメッセージの明示的な解決を求めることを、ブローカーに指示します。 受信クライアントが処理できるよう、メッセージに排他的なロックがかけられ、他の競合受信クライアントからは認識できなくなります。 ロックの有効期間は、当初キューまたはサブスクリプション レベルで定義され、ロックを所有しているクライアントによる RenewLock 操作によって延長できます。
受信操作の解決 / Settling receive operations
https://docs.microsoft.com/azure/service-bus-messaging/message-transfers-locks-settlement#settling-receive-operations
MQやJMSを知っている人になじみが深い挙動で、メッセージの取り扱いはクライアントに委ねられているため、明示的に完了を発行しなければメッセージはブローカーに滞留する(最大試行回数を超えると、Dead Letter Queueに入る)。
ReceiveAndDelete(受信して削除)
ブローカーは、ブローカーが受信クライアントに送信するすべてのメッセージを、送信時点で解決済みとみなします。 つまり、ブローカーが送信するとただちにメッセージは消費されたとみなされます。 メッセージの転送が失敗した場合、メッセージは失われます。
受信操作の解決 / Settling receive operations
このモードのメリットは、受信側メッセージでそれ以上のアクションを実行する必要はなく、解決の結果を待機する遅延も発生しないことです。 各メッセージに含まれるデータの価値が低い、またはデータが意味を持つ時間が非常に短時間の場合は、このモードは妥当な選択です。
https://docs.microsoft.com/azure/service-bus-messaging/message-transfers-locks-settlement#settling-receive-operations
「受け取ったらブローカー側には責任がない」ので、クライアント側で障害があった場合や受け取りに失敗した場合にメッセージをロストする可能性がある。データを入れる際のFire-forget形式に近い。データロストを避けたいのであれば、この方式は使うべきではない。
動作を確認する
今回はLogic Appを使って確認した。なお、Topicでも同様の挙動を示すため、Queueについてのみ紹介する。
PeekLock
Queueに入ったメッセージをPeekLockモードで受信し、Queue内のメッセージを完了せずに強制的にインスタンスを終了させるようなロジックアプリを作成した。Queueにメッセージを入れてこのロジックアプリが動作すると、Queueからはメッセージは削除されず、Retryが続いて最終的にDead Letter Queueにメッセージが入る。

続いて、Queue内のメッセージを完了させるよう「キュー内のメッセージを完了する」アクションを通すと、メッセージはQueueから消去される。

QueueのメッセージをDead Letter Queueに入れるように「キューのメッセージを配信不能にする」アクションを使うと、このタイミングでメッセージはDead Letter Queueに入り、ロックは解除される。そのため、このアクションの後に 「キュー内のメッセージを完了する」アクションを配置すると、すでにロックは存在しないので例外が発生する。

ReceiveAndDelete
Logic AppではこのモードはAuto Completeと呼ばれる。
PeekLockモードと同様に、Queueに入ったメッセージをReceiveAndDeleteモードで受信し、強制的にインスタンスを終了させるようなロジックアプリを作成した。Queueにメッセージを入れてこのロジックアプリが動作すると、Queueからメッセージは削除される。これはメッセージがQueueから取り出された時点でブローカーはメッセージを削除しているためである。

続いて、「キュー内のメッセージを完了する」アクションを通すようにすると、元々ロックされていないメッセージに対してロックの解放を指示しているので、例外が発生する。

Dead Letter Queueに入れるよう「配信不能にする」アクションを指定すると、これも「キュー内のメッセージを完了する」場合と同様、ロック対象ではないものに対してロックリリースをしようとして失敗する。

まとめ
Service BusのQueue/Topicについて受信時の挙動を確認した。今回はロジックアプリで確認したが、Javaでクライアントを記述する場合、PeekLockモードで受信する場合にはQueueClient#completeをお忘れなく。
Thanks great bllog post
いいねいいね