删除有害消息
“有害消息”是含有应用程序无法成功处理的信息的消息。例如,生产工作站可能恰好在更改命令弃用某个零件之前提交了一个请求,用以从库存中提取该零件。对库存的请求正在传输中时,更改命令开始生效。库存管理应用程序从工作站收到该请求,但无法成功处理它,而且更新存货中零件数的数据库操作也将失败。然后,包含接收操作的事务将回滚,并将该消息返回到队列中。在这种情况下,应用程序会继续收到这个消息,更新操作也将继续失败,然后该消息会再次返回到队列中。
有害的消息不是损坏的消息,而且可能是有效的请求。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 将放弃该会话的所有消息。请注意,通常处理消息的应用程序不接收此会话的 EndDialog 或 Error 消息。因此,如果该应用程序维护状态,则您必须在结束会话并返回错误后,小心地删除与该会话关联的状态。
如果服务无法处理某个消息,这表示该服务无法完成相应会话的任务。通过结束会话并返回一个错误,可以通知该会话的其他参与者该任务已失败。