SQL Server Service Broker 错误处理
我有一个存储过程,它将一条消息放入 SQL Server Service Broker 消息队列中。如果出现问题并且消息未放置在消息队列中,我需要从存储过程返回错误消息。我看到的问题是,即使 SQL Server Service Broker 被禁用(这就是我试图测试将消息放入队列的失败的方式),当我运行 TSQL 代码来放置时,它也不会返回错误队列中的消息。
有谁知道如何检测将消息放入 SQL Server Broker 消息队列是否失败?
I've got a stored procedure that puts a message on a SQL Server Service Broker message queue. I need to return an error message from the stored procedure if something goes wrong and the message doesn't get placed on the message queue. The problem I am seeing is that even if the SQL Server Service Broker is disabled (which is how I'm trying to test the failure to put a message on the queue) it doesn't return an error when I run TSQL code to put a message on the queue.
Does anyone know how to detect if putting a message on a SQL Server Broker message queue failed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Service Broker 不会将消息放入目标队列中。相反,被放入数据库传输队列中 (
sys.transmission_queue
)。提交 SEND 后,后台发送器将拾取消息,解析路由并将消息传递到其目的地。如果目标碰巧位于同一实例内,则在 SEND 语句本身期间尝试快捷传送路径,其中消息直接放入目标队列中。如果入队失败,则消息将被退回并放置在正常的传递路径中,即。放入sys.trasnmission_queu中。卡在
sys.transmission_queue
中的消息将有一个transmission_status
来解释消息无法传送的原因。系统将自动重新尝试这些消息。SEND 唯一可能返回错误的情况是当消息无法发送时,而不是当消息无法传送时。如果您尝试在已关闭的对话中
SEND
,或者存在一些非代理错误(只读数据库、日志已满、内存不足等)甚至阻止将消息接受到 <代码>sys.transmission_queue。这种甚至是异步和松散耦合的本地传递的行为是有意为之的,旨在帮助应用程序在目标队列是本地和目标队列是远程时表现相同。
在 Service Broker 中处理错误的方法是检查您自己的队列是否有响应。如果目标服务主动拒绝您的消息(即访问被拒绝、XML 格式错误或违反服务合同),那么它将以错误结束对话,并且您会在自己的队列中收到一条错误消息。如果您的消息根本无法传递,那么它将保留在传输队列中直到过期,然后会话因错误而结束,并且错误消息将再次放入您自己的队列中。在
BEGIN CONVERSATION
指定的生命周期到期后,消息将超时。因此,在您的情况下,当您禁用代理时,消息仍会被接受,但不会传递。它被放置在传输队列中。一旦您在数据库中重新启用代理,该消息就会被拾取并传递。当交付的可靠性是主要考虑因素时,这种行为使得应用程序的编写变得更加简单。应用程序只需发送即可知道,即使目的地不可用(例如,为了服务维护而关闭),消息也会到达那里,即使消息需要数小时、数天甚至数周才能到达。发表。对于还关心传递时间的应用程序,它们应该指定会话生命周期。系统将尝试在此生命周期内传递消息或放弃。如果它放弃,它会通过排队错误消息(会话超时错误)来通知发送者。
此外,应用程序不应等待响应。它们应该
SEND
、COMMIT
并继续,事件驱动。当目标发回响应时,或者当底层基础设施通知错误时,应用程序会在自己的队列中收到一条消息,并且应该对该消息做出反应。Service Broker does not place the message into the target queue. Instead is placed into the database transmissions queue (
sys.transmission_queue
). After the SEND is committed the message is picked up by the background transmitter, the routing is resolved and the message is delivered to its destination.If the destination happen to be located within the same instance then a shortcut delivery path is attempted during the SEND statement itself, in which the message is placed straight into the destination queue. If the enqueue fails, then the message is bounced back and placed in the normal delivery path, ie. put into
sys.trasnmission_queu
e. A message stuck insys.transmission_queue
will have atransmission_status
explaining why the message could not be delivered. The system will automatically re-attempt these messages.The only time when the SEND can return an error is when the message cannot be sent, not when it cannot be delivered. This would be if you try to
SEND
on a closed conversation or if there is some non-broker error (read only database, log full, out of memory etc) that prevents even accepting of the message intosys.transmission_queue
.This behavior of macking even a local delivery asynchronous and loosely coupled is intentional and is designed to help applications by behaving the same when the destination queue is local and when the destination queue is remote.
The way to handle errors in Service Broker is by checking your own queue for a response. If the destination service actively refuses your message (ie. access denied, or XML malformat, or service contract violation) then it will end the conversation with error and you get an error message back in your own queue. If your message simply cannot be delivered, then it will stay in transmission queue until it expires and then the conversation is ended with error, and again an error message will be placed into your own queue. Messages time out after the lifetime specified with
BEGIN CONVERSATION
expires.So in your case when you disable the broker the message is still accepted, but not delivered. It is placed in the transmsision queue. As soon as you enable back the broker in the database, that message will be picked up and delivered. This behavior makes application writing much simpler when reliability of delivery is the main concern. The app simply SENDs knowing that the message will get there even if the destination is not available (eg. taken down for service maintenance), even if it takes hours or days or even weeks for the message to be delivered. For applications that are concerned also with the timing of delivery, they should specify a conversation lifetime. The system will attempt to deliver the message within this lifetime or give up. If it gives up, it notifies the sender by enqueueing an error message (the conversation timeout error).
Also applications should not wait for a response. They should
SEND
,COMMIT
and continue, be event driven. When the target sends back a response, or when the underlying infrastructure notifies of an error, the application gets a message in its own queue and it should react to that message.