有害なメッセージの削除

有害なメッセージとは、アプリケーションが正常に処理できない情報を含んだメッセージのことです。たとえば、ある部品が変更オーダーで旧式とされる直前に、製造現場のワークステーションが、その部品を在庫から撤収するように要求するメッセージを送信したとします。変更オーダーは、在庫に対する要求が転送されている間に有効になります。在庫管理アプリケーションは、ワークステーションから要求を受信しますが、その要求を正常に処理することはできず、在庫している部品の数を更新するデータベース操作は失敗します。受信操作を含んだトランザクションはロールバックされ、メッセージはキューに戻されます。この状況では、アプリケーションは同じメッセージを受信し続け、更新は失敗し続け、メッセージはキューに戻されます。

有害なメッセージは、破損したメッセージではなく、無効な要求などでもありません。Service Broker には、破損したメッセージを検出するためのメッセージの整合性チェックが含まれています。また通常、アプリケーションはメッセージの内容も検証し、無効な要求を含んだメッセージは破棄します。一方、多くの有害なメッセージは、そのメッセージの作成時には有効だったものが、後に処理できなくなったものです。

有害なメッセージの自動検出

Service Broker では、有害なメッセージの自動検出が提供されます。RECEIVE ステートメントを含んだトランザクションが 5 回ロールバックすると、Service Broker は、キューの状態を自動的に OFF に設定することで、トランザクションが受信したメッセージの送信元であるすべてのキューを無効にします。さらに、Service Broker は、Broker:Queue Disabled という種類のイベントを生成します。

管理者は、SQL Server エージェントの警告を使用して、キューが無効化された際に通知を受け取ることができます。開発者は、Service Broker がキューを無効にした際に、それを検出するアプリケーションを作成することもできます。そのアプリケーションは、キュー内のメッセージを頻繁に検査して、有害なメッセージを検出します。処理不能なメッセージをアプリケーションで特定すると、キューの状態は ON に設定され、そのメッセージに関するメッセージ交換はエラーとして終了します。有害なメッセージを検出するアプリケーションは、メッセージ交換を終了する際に、そのメッセージ交換に関連するすべての状態を慎重にクリーンアップする必要があります。有害なメッセージから復旧するためのアプリケーションの作成方法の詳細については、「有害なメッセージの処理」を参照してください。

有害なメッセージの管理作業における削除

ほとんどのアプリケーションは、有害なメッセージをプログラムを使用して追跡および削除します。しかし、時には、有害なメッセージを手動で削除する必要が生じる場合があります。たとえば、復旧を実行するアプリケーションの中には、有害なメッセージを検出できないものや、メッセージ交換に関して保存されている状態を安全にクリーンアップできないものがあります。

メッセージを手動で削除すると、重要なメッセージ交換を中断する危険性があります。そのため、有害なメッセージをキューから削除する前に、必ずそのメッセージを検査してください。メッセージの内容を確認するには、トランザクションを開始し、メッセージ本文を受信して表示し、トランザクションをロールバックします。問題のメッセージが本当に有害なメッセージであることが確認できるまで、トランザクションをロールバックすることが重要です。

次の例に、キュー ExpenseQueue のメッセージ交換ハンドル e29059bb-9922-40f4-a575-66b2e4c70cf9 について、メッセージを安全に検査する方法を示します。

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 メッセージは受信しないことに注意してください。そのため、アプリケーションが状態を維持している場合、メッセージ交換をエラーで終了した後、メッセージ交換に関連付けられている状態を慎重に削除する必要があります。

サービスがメッセージを処理できない場合、サービスはそのメッセージ交換に関するタスクを完了していません。メッセージ交換がエラーで終了すると、メッセージ交換の他の参加者に対して、タスクが失敗したことが通知されます。