删除有害消息

“有害消息”是含有应用程序无法成功处理的信息的消息。例如,生产工作站可能恰好在更改命令弃用某个零件之前提交了一个请求,用以从库存中提取该零件。对库存的请求正在传输中时,更改命令开始生效。库存管理应用程序从工作站收到该请求,但无法成功处理它,而且更新存货中零件数的数据库操作也将失败。然后,包含接收操作的事务将回滚,并将该消息返回到队列中。在这种情况下,应用程序会继续收到这个消息,更新操作也将继续失败,然后该消息会再次返回到队列中。

有害的消息不是损坏的消息,而且可能是有效的请求。Service Broker 包含可检测损坏消息的消息完整性检查。应用程序通常也会验证消息的内容,并放弃包含非法请求的消息。相反,很多有害消息在它们被创建时是有效的,但之后却变成了无法处理的消息。

有害消息自动检测

Service Broker 提供了有害消息自动检测功能。当包含 RECEIVE 语句的事务回滚五次后,Service Broker 会自动将该事务从中接收消息的所有队列的状态设为 OFF,从而禁用这些队列。此外,Service Broker 还生成一个 Broker:Queue Disabled 类型的事件。

管理员可以使用 SQL Server 代理警报在禁用队列时得到通知。开发人员也可以创建一个应用程序,检测 Service Broker 何时禁用队列。该应用程序通常检查队列中的消息以查找有害消息。应用程序确定了无法处理的消息后,它会将队列状态设为 ON,结束该消息的会话并返回一个错误。在结束会话时,检测有害消息的应用程序必须小心清除任何与该会话关联的状态。有关创建用于从有害消息进行恢复的应用程序的详细信息,请参阅处理有害消息

以管理员角色删除有害消息

大多数应用程序都以编程方式跟踪和删除有害消息。但是,有时候可能需要手动删除有害消息。例如,部分执行恢复的应用程序可能无法检测有害消息,或者无法安全地清除会话的保存状态。

手动删除消息将面临中断重要会话的风险。因此,请务必先检查有害消息,再从队列中删除消息。若要查看消息的内容,请开始一个事务、接收消息正文、显示消息正文,然后回滚该事务。直到能够肯定相关消息是有害消息之前,回滚事务都十分必要。

示例

下面的示例演示如何安全地检查队列 ExpenseQueue 中会话句柄为 e29059bb-9922-40f4-a575-66b2e4c70cf9 的消息。

use AdventureWorks ;
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 ;

  -- Rollback 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 将放弃该会话的所有消息。请注意,通常处理消息的应用程序不接收此会话的 EndDialogError 消息。因此,如果该应用程序维护状态,则您必须在结束会话并返回错误后,小心地删除与该会话关联的状态。

如果服务无法处理某个消息,这表示该服务无法完成相应会话的任务。通过结束会话并返回一个错误,可以通知该会话的其他参与者该任务已失败。