我有一个存储过程,它将消息放在SQL Server Service Broker消息队列中。如果出现问题并且消息没有放在消息队列中,我需要从存储过程返回一条错误消息。我看到的问题是,即使SQL Server Service Broker被禁用(这是我试图测试无法将消息放入队列的方式),当我运行TSQL代码时,它不会返回错误队列中的消息。
有人知道如何检测在SQL Server Broker消息队列上放置消息是否失败?
答案 0 :(得分:20)
Service Broker不会将消息放入目标队列。而是放入数据库传输队列(sys.transmission_queue
)。在提交SEND之后,后台发送器接收消息,解析路由并将消息传送到其目的地。
如果目标恰好位于同一实例中,则在SEND语句本身期间尝试快捷方式传递路径,其中消息直接放入目标队列。如果入队失败,则消息被退回并放置在正常的传递路径中,即。放入sys.trasnmission_queu
e。卡在sys.transmission_queue
中的邮件将transmission_status
解释无法传递邮件的原因。系统将自动重新尝试这些消息。
SEND唯一可以返回错误的时间是消息无法发送,而不是无法发送。如果你在一个已关闭的对话上尝试SEND
,或者如果有一些非代理错误(只读数据库,日志已满,内存不足等),则会阻止甚至将消息接收到{{1} }。
这种对异步和松散耦合的本地传递进行macking的行为是故意的,旨在通过在目标队列是本地的以及目标队列是远程时表现相同来帮助应用程序。
在Service Broker中处理错误的方法是检查自己的队列以获取响应。如果目标服务主动拒绝您的消息(即拒绝访问,XML格式错误或服务合同违规),那么它将以错误结束对话,并在您自己的队列中收到错误消息。如果您的消息根本无法传递,那么它将一直保留在传输队列中,直到它过期,然后会以错误结束对话,并再次将错误消息放入您自己的队列中。消息在sys.transmission_queue
指定的生命周期结束后超时。
因此,在您禁用代理的情况下,仍然会接受消息,但不会传递消息。它被放置在transmsision队列中。只要在数据库中启用代理,就会拾取并传递该消息。当交付的可靠性是主要关注点时,此行为使应用程序编写更加简单。即使目的地不可用(例如,为了维护服务而取消),即使消息需要数小时,数天甚至数周,该应用程序只需发送消息将到达那里即可。交付。对于与交付时间有关的应用程序,它们应指定对话生存期。系统将尝试在此生命周期内传递消息或放弃。如果它放弃,它会通过排队错误消息(会话超时错误)来通知发件人。
此外,应用程序不应等待以获取响应。他们应该BEGIN CONVERSATION
,SEND
并继续事件驱动。当目标发回响应时,或者当底层基础结构通知错误时,应用程序会在其自己的队列中获取一条消息,并且应该对该消息做出反应。