SQL 服务器服务代理结束对话在启动器队列上创建新条目

SQL Server service broker end conversation creates new entries on initiator queue

我们正在使用 SQL Service Broker,为启动器和目标使用两个服务,然后我们有一个 C# 服务侦听和接收来自队列的消息。

在 SQL 端,设置是这样的:

    CREATE MESSAGE TYPE [http://mycompany.com/MyEventRequestMessage] VALIDATION = WELL_FORMED_XML
GO
CREATE MESSAGE TYPE [http://mycompany.com/MyEventResponseMessage] VALIDATION = WELL_FORMED_XML
GO

CREATE CONTRACT [http://mycompany.com/MyMessageContract] ([http://mycompany.com/MyEventRequestMessage] SENT BY INITIATOR,
[http://mycompany.com/MyEventResponseMessage] SENT BY TARGET)
GO

CREATE QUEUE [dbo].[MyEventInitiatorQueue] WITH STATUS = ON , RETENTION = OFF , POISON_MESSAGE_HANDLING (STATUS = ON)  ON [PRIMARY] 
GO
CREATE QUEUE [dbo].[MyEventTargetQueue] WITH STATUS = ON , RETENTION = OFF , POISON_MESSAGE_HANDLING (STATUS = ON)  ON [PRIMARY] 
GO

CREATE SERVICE [MyEventInitiatorService]  ON QUEUE [dbo].[MyEventInitiatorQueue] ([http://mycompany.com/MyMessageContract])
GO
CREATE SERVICE [MyEventTargetService]  ON QUEUE [dbo].[MyEventTargetQueue] ([http://mycompany.com/MyMessageContract])
GO

然后如果我插入一条消息:

DECLARE @MessageType NVARCHAR(128) = 'http://mycompany.com/MyEventRequestMessage'
DECLARE @MessageBody NVARCHAR(128) = 'loremipsum'
DECLARE @FromService NVARCHAR(128) = 'MyEventInitiatorService'
DECLARE @ToService NVARCHAR(128) = 'MyEventTargetService'
DECLARE @Contract NVARCHAR(128) = 'http://mycompany.com/MyMessageContract'

DECLARE @conversation_handle UNIQUEIDENTIFIER;
 
    BEGIN DIALOG CONVERSATION @conversation_handle
        FROM SERVICE @FromService
        TO SERVICE @ToService
        ON CONTRACT @Contract
        WITH ENCRYPTION = OFF;
 
    SEND ON CONVERSATION @conversation_handle   
        MESSAGE TYPE @MessageType(@MessageBody);

如期到达目标队列。

然后在服务上我们从目标队列接收消息并执行结束对话。

消息从目标队列中消失,但随后在启动器队列中插入一条类型为 http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog 的新消息。

尽管我们的服务已准备好结束这些对话,但它正在侦听目标队列。

我们如何清除这些结束对话消息?我们是否也应该在发起者队列中监听这些类型的消息,以便结束对话,或者我们应该做其他事情吗?

如果不采取任何措施,我们担心这是否会对数据库或服务器造成任何副作用。

谢谢。

How can we clear these end dialog messages? Should we listen also on the initiator queue these kind of messages, in order to end the conversation, or should we do anything else?

是的,您还需要一个服务(技术上是任何 SQL 进程)来侦听启动器队列消息,以便在收到 EndDialog 或 Error 消息时结束对话的那一侧。考虑记录任何意外消息类型(即 EndDialog 以外的消息类型)。

如果不采取任何措施,您最终会用不需要的启动器队列消息填满数据数据库,

我认为我们找到了符合 Dan 评论的解决方案:

CREATE PROCEDURE spHandleInitiatorQueueMessages

AS

DECLARE @dh UNIQUEIDENTIFIER;

DECLARE @message_type SYSNAME;

DECLARE @message_body NVARCHAR(4000);

BEGIN TRANSACTION;

WAITFOR (

      RECEIVE @dh = [conversation_handle],

            @message_type = [message_type_name],

            @message_body = CAST([message_body] AS NVARCHAR(4000))

      FROM MyInitiatorQueue), TIMEOUT 1000;

WHILE @dh IS NOT NULL

BEGIN

      IF @message_type = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'

          BEGIN

                RAISERROR (N'Received error %s from service [Target]', 10, 1, @message_body) WITH LOG;

          END

      END CONVERSATION @dh;

      COMMIT;

      SELECT @dh = NULL;

      BEGIN TRANSACTION;

      WAITFOR (

            RECEIVE @dh = [conversation_handle],

                  @message_type = [message_type_name],

                  @message_body = CAST([message_body] AS NVARCHAR(4000))

            FROM MyInitiatorQueue), TIMEOUT 1000;

END

COMMIT;

GO

 

ALTER QUEUE MyInitiatorQueue

      WITH ACTIVATION (

            STATUS = ON,

            MAX_QUEUE_READERS = 1,

            PROCEDURE_NAME = spHandleInitiatorQueueMessages,

            EXECUTE AS OWNER);

GO

消息开始实际结束