2012-08-03 83 views
2

几个星期以来,我一直与Service Broker一起工作,在跟踪对话的同时,我发现了一些奇怪的事情......对话似乎在队列中还有一个额外的消息,导致发生错误。SQL Server Service Broker队列对话对话框

从我的理解,对话对话框应该如下:

  1. 触发火灾和电话开始交谈
  2. 发起服务场所消息队列
  3. 目标服务大火一个存储过程,接收消息并结束对话
  4. 启动器服务触发存储的进程,接收消息并结束对话。

发生了什么是在队列末尾有一个额外的消息,它再次触发存储的proc,但细节(即conversation_handle)为空。它也会抛出一个错误:Conversion failed when converting from a character string to uniqueidentifier.为了解决这个错误,我将conversation_handle转换为varchar,然后检查null。对我来说似乎很愚蠢,我必须这样做。

更新:错误已经消失 - 我相信它发生时,我试图登录的conversation_handle(这是无效)。

什么是结束对话而不在最后得到额外消息的正确方法?

这是我现在有:

alter proc dbo.MessageProcessor 
as 

begin 

    set nocount on; 
    set xact_abort on; 

    declare @xactState smallint 

    declare @handle uniqueidentifier, 
      @responseXml xml, 
      @messageType sysname; 

    begin transaction; 
    begin try 

     ;receive top(1) 
      @messageType = message_type_name, 
      @handle = conversation_handle, 
      @responseXml = message_body 
     from dbo.MessageQueue 

     if(@handle is not null) 
     begin 

      if (@messageType = N'DEFAULT') 
      begin 

       save transaction MessageProcessor_Tran 

       begin try 

        -- doing work here 

       end try 
       begin catch 

        select @xactState = xact_state() 

        if(@xactState = -1) 
        begin 
         rollback; 
         raiserror(N'Unrecoverable error', 16, 1) 
        end 
        else if(@xactState = 1) 
        begin 
         rollback transaction MessageProcessor_tran 
        end 

        -- log error information 

       end catch 
      end 
      else if (@messageType = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error') 
      begin 
       declare @errorNumber int, 
         @errorMessage nvarchar(4000); 

       with xmlnamespaces (DEFAULT N'http://schemas.microsoft.com/SQL/ServiceBroker/Error') 
       select @errorNumber = @responseXml.value ('(/Error/Code)[1]', 'INT'), 
        @errorMessage = @responseXml.value ('(/Error/Description)[1]', 'NVARCHAR(4000)'); 
       -- log error 
      end 

      end conversation @handle 
      set @handle = null 
     end 

     commit 
    end try 

    begin catch 

     declare @error int, 
       @message nvarchar(2048) 

     select @error = error_number(), 
      @message = error_message(), 
      @xactState = xact_state(); 

     if(@xactState <> 0) 
      rollback; 

     if(@handle is not null) 
      end conversation @handle; 

     -- log error    
     raiserror(N'Error: %i, %s', 1, 60, @error, @message) with log; 

    end catch 
end 
go 
+0

什么是您的“流氓”消息的消息类型? – 2012-08-03 01:31:59

+0

它也是NULL。 – 2012-08-03 01:34:05

回答

2

没有任何额外的信息。只是你的程序在空队列上被激活。您激活的过程代码应该被激活,并且RECEIVE会每隔一段时间返回一个空的行集(如果您每次只用一条消息测试它,就会发生每次都如您所见的实际负载情况,它很少会发生) 。

在您的代码中,这种情况(接收空结果集)将反映在NULL @handle,NULL @messageType和NULL @responseXML中,这几乎就是您所描述的。

+0

再次感谢Remus。 – 2012-08-03 20:08:34