我正试图开始使用SQL Server Service Broker来审核异步Intranet应用程序用户的行为。
我已经创建了消息,合同,队列和服务。设置一个过程以在激活此队列时触发。
到目前为止,太好了。邮件正在发送和接收。
该过程从该队列中接收前1条消息,然后执行所需的操作(基本上是插入表中)并退出。
我的问题:接收消息的过程是否需要无限循环?队列的MAX_QUEUE_READERS
设置为2。是否意味着不管队列中的消息数量如何,总是将有2个实例在运行该过程?
答案 0 :(得分:2)
是的,最好在激活过程中进行循环。简而言之,Service Broker仅在新消息到达队列时才调用您的激活过程。但是,如果过程已经在运行,并且MAX_QUEUE_READERS池已用尽,则无法产生任何其他处理线程。
这样,如果队列的填充速度快于过程完成其工作的速度,您将开始看到未处理的消息开始在队列中累积。
另一件事是,调用过程会产生额外的开销,尽管很小。如果您尝试通过增加MAX_QUEUE_READERS值来缓解问题,最终您可能会开始注意到这种开销。那样,它仍然不能保证将处理所有消息,并且不会忘记所有消息。
以下是用于此过程的典型骨架结构,如果要构建可靠的,有弹性的系统,则应遵循以下方法:
create procedure [dbo].[ssb_QProcessor_MyQueue]
with execute as owner as
set nocount, ansi_nulls, ansi_padding, ansi_warnings, concat_null_yields_null, quoted_identifier, arithabort on;
set numeric_roundabort, xact_abort, implicit_transactions off;
declare @Handle uniqueidentifier, @MessageType sysname, @Body xml;
declare @Error int, @ErrorMessage nvarchar(2048), @ProcId int = @@procid;
-- Fast entry check for queue contents
if not exists (select 0 from dbo.MySBQueueName with (nolock))
return;
while exists (select 0 from sys.service_queues where name = 'MySBQueueName' and is_receive_enabled = 1) begin
begin try
begin tran;
-- Receive something, if any
waitfor (
receive top (1) @Handle = conversation_handle,
@MessageType = message_type_name,
@Body = message_body
from dbo.MySBQueueName
), timeout 3000;
if @Handle is null begin
-- Empty, get out
rollback;
break;
end;
-- Whatever processing logic you have should be put here
commit;
end try
begin catch
if nullif(@Error, 0) is null
select @Error = error_number(), @ErrorMessage = error_message();
-- Check commitability of the transaction
if xact_state() = -1
rollback;
else if xact_state() = 1
commit;
-- Try to resend the message again (up to you)
exec dbo.[ssb_Poison_Retry] @MessageType = @MessageType, @MessageBody = @Body,
@ProcId = @ProcId, @ErrorNumber = @Error, @ErrorMessage = @ErrorMessage;
end catch;
-- Reset dialog handle
select @Handle = null, @Error = null, @ErrorMessage = null;
end;
-- Done!
return;