3

我有一个将消息放入 SQL Server Service Broker 消息队列的存储过程。如果出现问题并且消息没有放在消息队列中,我需要从存储过程返回错误消息。我看到的问题是,即使禁用了 SQL Server 服务代理(这是我试图测试将消息放入队列失败的方式),当我运行 TSQL 代码放置时它不会返回错误队列中的一条消息。

有谁知道如何检测将消息放入 SQL Server Broker 消息队列是否失败?

4

1 回答 1

20

Service Broker 不会将消息放入目标队列。而是放入数据库传输队列 ( sys.transmission_queue)。在提交 SEND 后,消息被后台发送器拾取,路由被解析并将消息传递到其目的地。

如果目标恰好位于同一实例中,则在 SEND 语句本身期间尝试使用快捷传递路径,其中消息直接放入目标队列中。如果入队失败,则将消息退回并放置在正常的传递路径中,即。放入sys.trasnmission_queue。卡住的消息sys.transmission_queuetransmission_status解释为什么无法传递消息。系统将自动重新尝试这些消息。

SEND 可以返回错误的唯一时间是无法发送消息,而不是无法传递消息。如果您尝试进行SEND封闭式对话,或者存在一些非代理错误(只读数据库、日志已满、内存不足等),甚至无法将消息接收到sys.transmission_queue.

这种使本地交付异步和松散耦合的行为是有意的,旨在通过在目标队列是本地的和目标队列是远程的时表现相同来帮助应用程序。

在 Service Broker 中处理错误的方法是检查您自己的队列以获取响应。如果目标服务主动拒绝您的消息(即访问被拒绝、XML 格式错误或违反服务合同),那么它将以错误结束对话,并且您会在自己的队列中返回一条错误消息。如果您的消息根本无法传递,那么它将保留在传输队列中直到它过期,然后对话以错误结束,并且再次将错误消息放入您自己的队列中。消息在用BEGIN CONVERSATIONexpires 指定的生命周期后超时。

因此,在您禁用代理的情况下,消息仍被接受,但未传递。它被放置在传输队列中。一旦您在数据库中启用代理,该消息将被拾取并传递。当交付的可靠性是主要关注点时,此行为使应用程序编写更加简单。该应用程序只是发送知道该消息即使目的地不可用(例如,因服务维护而停机),即使需要数小时或数天甚至数周才能传递消息,也要到达那里。对于还关注交付时间的应用程序,它们应该指定会话生命周期。系统将尝试在此生命周期内传递消息或放弃。如果它放弃,它会通过将错误消息排入队列来通知发送者(会话超时错误)。

此外,应用程序不应等待响应。它们应该并且继续是事件驱动SEND的。当目标发回响应时,或者当底层基础设施通知错误时,应用程序会在自己的队列中获取一条消息,并且应该对该消息做出反应。COMMIT

于 2009-09-30T16:58:51.050 回答