Sql server 2012 Can';不要关闭ServiceBroker对话

Sql server 2012 Can';不要关闭ServiceBroker对话,sql-server-2012,service-broker,Sql Server 2012,Service Broker,我在结束ServiceBroker对话时遇到问题,我想从概念上理解事情应该如何运作。 请注意,我的代码基于Dan Guzman的示例 给定以下SQL Server 2012 Service Broker配置: 发起者 启动器服务-内部激活 目标 目标队列监视器 外部激活器服务(与REST服务通信的SSIS应用程序) 这是我对流程的理解: 发起程序向目标发送消息 目标队列通知事件激发 外部激活器服务执行以响应目标队列通知事件;问题接收TOP(1)以检索发送到目标的消息 External Act

我在结束ServiceBroker对话时遇到问题,我想从概念上理解事情应该如何运作。 请注意,我的代码基于Dan Guzman的示例

给定以下SQL Server 2012 Service Broker配置:

  • 发起者
  • 启动器服务-内部激活
  • 目标
  • 目标队列监视器
  • 外部激活器服务(与REST服务通信的SSIS应用程序)
这是我对流程的理解:

  • 发起程序向目标发送消息
  • 目标队列通知事件激发
  • 外部激活器服务执行以响应目标队列通知事件;问题接收TOP(1)以检索发送到目标的消息
  • External Activator服务完成处理并执行END CONVERSATION@ConversationHandle
  • 步骤4的结束对话会向发起人发送一条关闭消息;启动器的内部激活服务运行以响应启动器队列中出现的消息,进行处理并发出END CONVERSATION@ConversationHandle
  • 不幸的是,对话的发起方结束了,但目标方从未结束;它处于断开连接的状态

    当External Activator服务发出END conversation@ConversationHandle时,会话的目标端不会关闭吗?如果没有,如何结束对话的目标端

            -- Enabling service broker
            USE master
            ALTER DATABASE my_database
            SET ENABLE_BROKER; 
    
            --Create Message Types for Request and Response messages
    
            -- For Request
            CREATE MESSAGE TYPE
            [ABCEventRequestMessage]
            VALIDATION=WELL_FORMED_XML; 
    
            -- For Response
            CREATE MESSAGE TYPE
            [ABCEventResponseMessage]
            VALIDATION=WELL_FORMED_XML; 
    
            --Create Contract for the Conversation 
    
            CREATE CONTRACT [ABCEventContract]
            (
                [ABCEventRequestMessage] SENT BY INITIATOR 
                -- must make the reply message 'SENT BY ANY'
                -- so the External Activator service can
                -- send it to the Initiator after talking
                -- to the webservice
                ,[ABCEventResponseMessage] SENT BY ANY
            );
    
            --Create Queue for the Initiator
            CREATE QUEUE ABCEventInitiatorQueue
            WITH STATUS = ON,
            ACTIVATION (
              PROCEDURE_NAME = dbo.pci_LogABCEventTransferResult,
              MAX_QUEUE_READERS = 1,
              EXECUTE AS SELF
            ); 
    
            --Create Queue for the Target
            CREATE QUEUE ABCEventTargetQueue; 
    
            --Create Queue for the External Activator
           CREATE QUEUE ExternalActivatorQueue;
    
            --Create Service for the Target and the Initiator.
    
            --Create Service for the Initiator.
            -- NOTE: not specifying a contract on the queue
            -- means that the service can initiate conversations
            -- but it can't be a target for any other services
            CREATE SERVICE [ABCEventInitiatorService]
            ON QUEUE ABCEventInitiatorQueue;
    
            --Create Service for the Target.
            CREATE SERVICE [ABCEventTargetService] 
            ON QUEUE ABCEventTargetQueue
            ([ABCEventContract]); 
    
            --Create Service for the External Activator
            CREATE SERVICE ExternalActivatorService
            ON QUEUE ExternalActivatorQueue
            (
              [http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]
            );
    
          CREATE EVENT NOTIFICATION EventNotificationABCEventTargetQueue
              ON QUEUE ABCEventTargetQueue
              FOR QUEUE_ACTIVATION
              TO SERVICE 'ExternalActivatorService', 'current database';
        });
    






    这里有两个对话。一个是您自己的应用程序对话,一个是通知EA的系统对话。从您描述代码的方式来看,您依赖EA来关闭对话,但这只会关闭系统对话。您还需要关闭应用程序对话,即从目标队列接收的句柄

    更新:

    您激活的服务应发出<代码>接收。。。从目标,然后在收到的@handle上结束对话。你的解释说这就是你要做的(第4步),但如果你这样做,那么目标对话将在30分钟内彻底结束

    但是,您注意到会话处于断开连接的入站状态。这是一个已收到EndDialog消息但应用程序未对其发出结束转换的对话


    因此,您所解释的应用程序正在执行的操作与观察到的对话状态之间存在脱节。我猜代码中可能有一个bug,而代码并没有完全按照您认为的那样执行。请尝试在此处发布代码的相关部分。

    感谢您的回复。如果EA服务发出END CONVERSATION@ConversationHandle不足以关闭应用程序对话,我将在何处执行END CONVERSATION以关闭我的应用程序对话。你能给我举个例子吗?在
    pci\u GetABCEventDetails
    中,你从
    ABCEventTargetQueue
    中退出队列,插入
    ABCEventTransferLog
    并提交。在
    pci\u CompleteABCEventTransfer
    中,您可以结束对话,但不清楚是否传入了正确的对话句柄。
            IF OBJECT_ID('dbo.pci_InitiateABCEventTransfer', 'P') IS NULL
            BEGIN
              EXEC ('CREATE PROCEDURE dbo.pci_InitiateABCEventTransfer as SELECT 1')
            END;
    
            ALTER PROC dbo.pci_InitiateABCEventTransfer
    
            @CompleteTriggerXMLOut XML = NULL OUTPUT
            ,@ConversationHandle uniqueidentifier = NULL OUTPUT
            ,@CompleteTriggerXMLIn XML
    
            ---------------------------------------------
            --called by application to trigger batch process
            --Sample Usage:
            --
            -- EXEC dbo.pci_InitiateABCEventTransfer @@CompleteTriggerXML = 'your_xml_here';
            -- NOTE: when calling this stored procedure from a SQL Server Mgmt
            -- Studio query window, enclose the xml data in single quotes;
            -- if you use double quotes instead, SQL Server thinks
            -- you are specifying a field name in which to save the data
            -- and returns an error like 'Maximum length is 128'
            ---------------------------------------------
            AS
            DECLARE
            --@conv_hand uniqueidentifier
            @message_body varbinary(MAX);
    
            SET @CompleteTriggerXMLOut = @CompleteTriggerXMLin
    
            BEGIN TRY
    
            BEGIN TRAN;
    
            BEGIN DIALOG CONVERSATION @ConversationHandle
            FROM SERVICE ABCEventInitiatorService
            TO SERVICE 'ABCEventTargetService', 'CURRENT DATABASE'
            ON CONTRACT ABCEventContract
            WITH
            ENCRYPTION = OFF,
            LIFETIME = 6000;
    
            -- NOTE: because we created our services with a specific
            -- contract, ABCEventContract, that includes specific
            -- message types (ABCEventRequestMessage & ABCEventResponseMessage)
            -- but does not include the DEFAULT message type,
            -- we must include the MESSAGE TYPE clause
            -- of the SEND ON CONVERSATION command; without this clause,
            -- Service Broker will assume the DEFAULT message type
            -- and the SEND will fail, saying, "The message TYPE 'DEFAULT'
            -- is not part of the service contract."
    
            SEND ON CONVERSATION @ConversationHandle
            MESSAGE TYPE ABCEventRequestMessage
            (@CompleteTriggerXMLOut);
    
            COMMIT;
            END TRY
            BEGIN CATCH
            THROW;
            END CATCH;
    
            SELECT @CompleteTriggerXMLOut, @ConversationHandle;
    
            PRINT 'CompleteTriggerXMLOut = ' + CONVERT(nvarchar(max), @CompleteTriggerXMLOut);
    
            RETURN @@ERROR; 
    
            IF OBJECT_ID('dbo.pci_GetABCEventDetails', 'P') IS NULL
            BEGIN
              EXEC ('CREATE PROCEDURE dbo.pci_GetABCEventDetails as SELECT 1')
            END;
    
            ALTER PROC dbo.pci_GetABCEventDetails
            --------------------------------------
            --called by SSIS package at start ---
            --------------------------------------
            AS
            DECLARE
            @conversation_handle uniqueidentifier
            ,@message_type_name sysname
            ,@message_body xml
            ,@parameter1 int;
    
            BEGIN TRY
    
            BEGIN TRAN;
    
            RECEIVE TOP(1)
            @conversation_handle = conversation_handle
            ,@message_type_name = message_type_name
            ,@message_body = message_body
            FROM dbo.ABCEventTargetQueue;
    
            IF @@ROWCOUNT = 0
            BEGIN
            RAISERROR ('No messages received from dbo.ABCEventTargetQueue', 16, 1);
            RETURN 1;
            END;
    
            INSERT INTO dbo.ABCEventTransferLog(
            ConversationHandle
            ,MessageTypeName
            ,MessageBody
            )
            VALUES(
            @conversation_handle
            ,@message_type_name
            ,CAST(@message_body AS varbinary(MAX))
            );
    
            COMMIT;
    
            SELECT
                CAST(@message_body AS nvarchar(MAX)) AS WhatIsThis
                ,@conversation_handle AS ConversationHandle
                ,@parameter1 AS Parameter1;
    
            END TRY
            BEGIN CATCH
            THROW;
            END CATCH;
    
            RETURN @@ERROR;
    
            IF OBJECT_ID('dbo.pci_CompleteABCEventTransfer', 'P') IS NULL
            BEGIN
              EXEC ('CREATE PROCEDURE dbo.pci_CompleteABCEventTransfer as SELECT 1')
            END;
    
                ALTER PROC dbo.pci_CompleteABCEventTransfer
              @ConversationHandle uniqueidentifier
                    ,@WebserviceResponseStatusCode integer
                    ,@WebserviceResponseXML xml
               ------------------------------------------
               -- called by SSIS package at completion
               -- Sample Usage:
    
               -- normal completion:
               -- EXEC dbo.pci_CompleteABCEventTransfer
               -- @ConversationHandle = '00000000-0000-0000-0000-000000000000';
    
               -- completed with error:
               -- EXEC dbo.pci_CompleteABCEventTransfer
               -- @ConversationHandle = '00000000-0000-0000-0000-000000000000'
               -- @ErrorMessage = 'an error occurred';
               ------------------------------------------
             AS
    
             IF @WebserviceResponseStatusCode <> 201
                   -- webservice record creation failed;
                   -- complete conversation with error
             BEGIN
               END CONVERSATION @ConversationHandle
               WITH ERROR = 1
               DESCRIPTION = 'Something went horribly wrong';
             END;
                   -- webservice created record in remote system;
                   -- complete conversation normally
                   ELSE
             BEGIN
               END CONVERSATION @ConversationHandle;
             END
    
             RETURN @@ERROR;
    
      # because of circular references, must create a "dummy"
      # LogABCEventTransferResult stored procedure first,
      # create the ABCEventInitiatorQueue and then replace
      # the dummy stored procedure with the real one
    
          IF OBJECT_ID('dbo.pci_LogABCEventTransferResult', 'P') IS NULL
          BEGIN
            EXEC ('CREATE PROCEDURE dbo.pci_LogABCEventTransferResult as SELECT 1')
          END;
    
          ALTER PROC dbo.pci_LogABCEventTransferResult
          ---------------------------------------------
          --initiator queue activated proc to process messages
          ---------------------------------------------
          AS
          DECLARE
          @conversation_handle uniqueidentifier
          ,@message_type_name sysname
          ,@message_body varbinary(MAX);
          WHILE 1 = 1
          BEGIN
          WAITFOR (
            RECEIVE TOP (1)
            @conversation_handle = conversation_handle
            ,@message_type_name = message_type_name
            ,@message_body = message_body
            FROM dbo.ABCEventInitiatorQueue
          ), TIMEOUT 1000;
          IF @@ROWCOUNT = 0
          BEGIN
          --exit when no more messages
          RETURN;
          END;
    
          --log message
          INSERT INTO dbo.ABCEventTransferLog(
            ConversationHandle
            ,MessageTypeName
            ,MessageBody
          )
          VALUES(
            @conversation_handle
            ,@message_type_name
            ,@message_body
          );
          END CONVERSATION @conversation_handle;
          END;
    
          --log table
          CREATE TABLE dbo.ABCEventTransferLog(
          ConversationHandle uniqueidentifier NOT NULL
          ,MessageTypeName sysname NOT NULL
          ,MessageBody varbinary(MAX) NULL
          ,LogTime datetime2(3) NOT NULL
          CONSTRAINT DF_ServiceBrokerLog_LogTime
          DEFAULT (SYSDATETIME())
          );
          CREATE CLUSTERED INDEX cdx_ABCEventTransferLog ON dbo.ABCEventTransferLog(LogTime);