適用対象:SQL Server
Azure SQL Managed Instance
有害なメッセージとは、アプリケーションが正常に処理できない情報を含んだメッセージのことです。 たとえば、ある部品が変更オーダーで旧式とされる直前に、製造現場のワークステーションが、その部品を在庫から撤収するように要求するメッセージを送信したとします。 変更オーダーは、在庫に対する要求が転送されている間に有効になります。 在庫管理アプリケーションは、ワークステーションから要求を受信しますが、その要求を正常に処理することはできず、在庫している部品の数を更新するデータベース操作は失敗します。 受信操作を含んだトランザクションはロールバックされ、メッセージはキューに戻されます。 この状況では、アプリケーションは同じメッセージを受信し続け、更新は失敗し続け、メッセージはキューに戻されます。
有害なメッセージは、破損したメッセージではなく、無効な要求などでもありません。 Service Broker には、破損したメッセージを検出するためのメッセージの整合性チェックが含まれています。 また通常、アプリケーションはメッセージの内容も検証し、無効な要求を含んだメッセージは破棄します。 一方、多くの有害なメッセージは、そのメッセージの作成時には有効だったものが、後に処理できなくなったものです。
有害なメッセージの自動検出
Service Broker では、有害なメッセージの自動検出が提供されます。 RECEIVE ステートメントを含んだトランザクションが 5 回ロールバックすると、Service Broker は、キューの状態を自動的に OFF に設定することで、トランザクションが受信したメッセージの送信元であるすべてのキューを無効にします。 また、Service Broker は、型 Broker:Queue Disabled のイベントを生成します。
管理者は、SQL Server エージェントの警告を使用して、キューが無効化されたときに通知を受け取ることができます。 開発者は、Service Broker がキューを無効にした際に、それを検出するアプリケーションを作成することもできます。 そのアプリケーションは、キュー内のメッセージを頻繁に検査して、有害なメッセージを検出します。 処理不能なメッセージをアプリケーションで特定すると、キューの状態は ON に設定され、そのメッセージに関するメッセージ交換はエラーとして終了します。 有害なメッセージを検出するアプリケーションは、メッセージ交換を終了する際に、そのメッセージ交換に関連するすべての状態を慎重にクリーンアップする必要があります。 有害なメッセージから復旧するアプリケーションの作成方法の詳細については、「有害メッセージの処理」を参照してください。
管理的に有害メッセージを削除する
ほとんどのアプリケーションは、有害なメッセージをプログラムを使用して追跡および削除します。 しかし、時には、有害なメッセージを手動で削除する必要が生じる場合があります。 たとえば、復旧を実行するアプリケーションの中には、有害なメッセージを検出できないものや、メッセージ交換に関して保存されている状態を安全にクリーンアップできないものがあります。
メッセージを手動で削除すると、重要なメッセージ交換を中断する危険性があります。 そのため、有害なメッセージをキューから削除する前に、必ずそのメッセージを検査してください。 メッセージの内容を確認するには、トランザクションを開始し、メッセージ本文を受信して表示し、トランザクションをロールバックします。 問題のメッセージが本当に有害なメッセージであることが確認できるまで、トランザクションをロールバックすることが重要です。
例
次のサンプルは、会話ハンドル e29059bb-9922-40f4-a575-66b2e4c70cf9 のメッセージをキュー ExpenseQueue 内で安全に検査する方法を示しています。> [!ノート/メモ]
> この記事のコード サンプルは、AdventureWorks2022
サンプル データベースを使用してテストされました。このデータベースは、Microsoft SQL Server サンプルとコミュニティ プロジェクト ホーム ページからダウンロードできます。
use AdventureWorks2008R2 ;
GO
-- Sample to show the content of a message, then return
-- the message to the queue. This may be useful to determine
-- whether a specific message cannot be processed due to the
-- content of the message.
-- Every exit path from the transaction rolls back the transaction.
-- This code is intended to inspect the message, not remove the
-- message from the queue permanently. The transaction must roll
-- back to return the message to the queue.
BEGIN TRANSACTION ;
-- To print the body, the code needs the message_body and
-- the encoding_format.
DECLARE @messageBody VARBINARY(MAX),
@validation NCHAR ;
-- Receive the message. The WAITFOR handles the case where
-- an application is attempting to process the message when
-- this batch is submitted. Replace the name of the queue and
-- the conversation_handle value.
WAITFOR(
RECEIVE TOP(1)
@messageBody = message_body,
@validation = validation
FROM dbo.ExpenseQueue
WHERE conversation_handle =
'e29059bb-9922-40f4-a575-66b2e4c70cf9'
), TIMEOUT 2000 ;
-- Roll back and exit if the message is not available
-- in two seconds.
IF @@ROWCOUNT = 0
BEGIN
ROLLBACK TRANSACTION ;
PRINT 'No message available.' ;
RETURN ;
END
-- Print the message based on the encoding format of
-- the message body.
IF (@validation = 'E')
BEGIN
PRINT 'Empty message.' ;
END ;
ELSE IF (@validation = 'X')
BEGIN
PRINT CONVERT(nvarchar(MAX), @messageBody) ;
END ;
ELSE IF (@validation = 'N')
BEGIN
PRINT 'No validation -- binary message:'
PRINT @messageBody ;
END
ROLLBACK TRANSACTION
GO
有害なメッセージを検出したら、メッセージ交換を終了します。 次のサンプルは、会話 e29059bb-9922-40f4-a575-66b2e4c70cf9 を終了させます。
-- End the conversation. Do this only if the message cannot be
-- processed by the normal procedure.
END CONVERSATION 'e29059bb-9922-40f4-a575-66b2e4c70cf9'
WITH ERROR = 127 DESCRIPTION = N'Unable to process message.' ;
GO
メッセージ交換を終了すると、Service Broker はそのメッセージ交換のメッセージを破棄します。 通常であればメッセージを処理するアプリケーションは、この会話に関する EndDialog メッセージまたは Error メッセージは受信しないことにご注意ください。 そのため、アプリケーションが状態を維持している場合、メッセージ交換をエラーで終了した後、メッセージ交換に関連付けられている状態を慎重に削除する必要があります。
サービスがメッセージを処理できない場合、サービスはそのメッセージ交換に関するタスクを完了していません。 メッセージ交換がエラーで終了すると、メッセージ交換の他の参加者に対して、タスクが失敗したことが通知されます。