Service Broker アプリケーションの概要
多くの Service Broker アプリケーションでは、メッセージを受信して処理する際に同じ基本手順を使用します。その基本手順を以下に示します。
アプリケーションがトランザクションを開始します。
状態を保持する場合は、メッセージ交換グループ ID を取得します。取得した ID を使用して、状態を状態テーブルから復元します。メッセージ交換グループに受信準備ができているメッセージがない場合は、トランザクションをロールバックし終了します。
キューから 1 つ以上のメッセージを受信します。メッセージ交換グループ ID を保持している場合は、そのメッセージ交換グループ ID を使用して対象のメッセージ交換グループのメッセージを受信します。使用できる受信済みのメッセージがなくなったら、トランザクションをコミットし、手順 1. に戻ります。
メッセージ型名に基づいてメッセージの内容を検証します。
メッセージ型名とメッセージの内容に基づいてメッセージを処理します。
処理結果のメッセージをすべて送信します。
状態を保持する場合、状態テーブルを更新します。この更新処理では、テーブルの主キーにメッセージ交換グループ ID を使用します。
手順 3. に戻り、これ以上使用できる受信済みのメッセージがないかどうかを確認します。
アプリケーションの厳密な構造は、アプリケーションの要件、アプリケーションの通信方式、アプリケーションが発信先サービスと発信側サービスのどちらであるか、および Service Broker がアプリケーションをアクティブ化しているかどうかによって異なります。
たとえば、発信側アプリケーションは、上記の手順で示した処理ループを開始する前に、メッセージを送信します。発信側サービスは別のプログラムまたはストアド プロシージャを使用してメッセージを送信し、その後発信側サービス キューに対してアクティブ化ストアド プロシージャを使用できます。たとえば、受注アプリケーションでは、注文を入力するためにメッセージ交換を開始する外部アプリケーションを実装できます。注文が入力された後、外部アプリケーションを実行したままにする必要はありません。発信側サービスのアクティブ化ストアド プロシージャは、受注サービスから応答が返ってきたら受注確認を送信します。また、アクティブ化ストアド プロシージャは、発信先サービスから返される Service Broker エラー メッセージを処理し、注文を確認できなかったことを示す通知を送信する処理も行います。
その他の方法として、別のプログラムからメッセージを送信するのではなく、発信側アプリケーションがメッセージを送信してから、同じプログラムの一環として処理ループを開始する場合もあります。どちらの方法でも、基本手順の概要は同じです。
1 つのメッセージ交換グループ内の大量のメッセージを処理するアプリケーションでは、一定量のメッセージを処理した後、受信したメッセージの数を保持しトランザクションをコミットすることができます。この数を保持してコミットする方法を使用すると、トランザクションが比較的短くなり、アプリケーションは別のメッセージ交換グループを処理できます。
例
次の Transact-SQL の例では、MyServiceQueue キューにあるすべてのメッセージを処理します。ここに示すメッセージの処理は、最低限必要な処理です。メッセージが EndDialog または Error メッセージの場合、メッセージ交換を終了します。他のメッセージの場合、メッセージの XML 表記が作成され、メッセージ交換ハンドル、メッセージ型名、および作成された XML を含んだ結果セットを生成します。500 ミリ秒間処理できるメッセージがなかった場合はコードが終了します。
単純にするために、このスクリプトではメッセージごとに結果セットを生成します。キューからの読み取り中にエラーが発生した場合、結果を生成せずに変更をコミットします。したがって、エラーが発生したメッセージはすべて自動的に削除されます。
注意 |
---|
このスクリプトはメッセージを表示するだけなので、有害なメッセージには対応していません。そのため、スクリプトには有害なメッセージを処理するコードが含まれていません。実稼働環境で使用するアプリケーションには、有害なメッセージを処理するコードを記述してください。有害なメッセージの詳細については、「有害なメッセージの処理」を参照してください。 |
USE AdventureWorks ;
GO
-- Process all conversation groups.
WHILE (1 = 1)
BEGIN
DECLARE @conversation_handle UNIQUEIDENTIFIER,
@conversation_group_id UNIQUEIDENTIFIER,
@message_body XML,
@message_type_name NVARCHAR(128);
-- Begin a transaction, one per conversation group.
BEGIN TRANSACTION ;
-- Get next conversation group.
WAITFOR(
GET CONVERSATION GROUP @conversation_group_id FROM MyServiceQueue),
TIMEOUT 500 ;
-- Restore the state for this conversation group here
-- If there are no more conversation groups, break.
IF @conversation_group_id IS NULL
BEGIN
ROLLBACK TRANSACTION ;
BREAK ;
END ;
-- Process all messages in the conversation group.
WHILE 1 = 1
BEGIN
-- Get the next message.
RECEIVE
TOP(1)
@conversation_handle = conversation_handle,
@message_type_name = message_type_name,
@message_body =
CASE
WHEN validation = 'X' THEN CAST(message_body AS XML)
ELSE CAST(N'<none/>' AS XML)
END
FROM MyServiceQueue
WHERE conversation_group_id = @conversation_group_id;
-- If there is no message, or there is an error
-- reading from the queue, break.
IF @@ROWCOUNT = 0 OR @@ERROR <> 0
BREAK;
-- Process the message. In this case, the program ends the conversation
-- for Error and EndDialog messages. For all other messages, the program
-- produces a result set with information about the message.
SELECT @conversation_handle,
@message_type_name,
@message_body ;
-- If the message is an end dialog message or an error,
-- end the conversation. Notice that other conversations
-- in the same conversation group may still have messages
-- to process. Therefore, the program does not break after
-- ending the conversation.
IF @message_type_name =
'https://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
OR @message_type_name =
'https://schemas.microsoft.com/SQL/ServiceBroker/Error'
BEGIN
END CONVERSATION @conversation_handle ;
END ;
END ; -- Process all messages in conversation group.
COMMIT TRANSACTION ;
END ; -- Process all conversation groups.