4

我们最近发现我们的一个数据库存在问题,由于“触发后忘记”设置(即:发送后立即关闭对话),我们的 sys.conversation_endpoints 表被 DI/DISCONNECTED_INBOUND 消息填满。这最终溢出到 tempDB 中,导致它急剧增长并占用宝贵的磁盘空间。我们最终通过注释掉该行解决了这个问题

END CONVERSATION @handle WITH CLEANUP

在我们的发送 SP 中并使用相同的代码关闭我们接收 SP 中的对话,

END CONVERSATION @handle WITH CLEANUP

但是,我们现在有一个新问题。自从移动服务器(并从 SQL Server 2005 迁移到 SQL Server 2008)以来,我们最近发现 sys.conversation_endpoints 现在充满了 CO/CONVERSING 消息,表明对话没有关闭。接收 SP 正在关闭它们,或者至少正在运行命令来这样做,所以我不明白这些消息来自哪里。

我尝试在发送时返回结束对话,但没有任何效果。使用 结束接收端的对话是错误的WITH CLEANUP吗?还是有其他问题?

techtarget 上的这篇文章似乎暗示它是一个错误,并且运行清理剩余物的工作是唯一的解决方案......

更新:Pawel 在下面指出,我应该避免使用 Fire & Forget 模式,并且我已将激活的 SP 添加到发起程序队列以结束任何对话。但是,sys.conversation_endpoints 仍然被填满,这次是 CD/CLOSED 消息。这是我的队列的结构

发送_SP:

DECLARE @h UNIQUEIDENTIFIER 
BEGIN DIALOG CONVERSATION @h 
FROM SERVICE 'InitiatorQueue' TO SERVICE 'TargetQueue' 
ON CONTRACT 'MyContract' WITH ENCRYPTION = OFF; 
SEND ON CONVERSATION @h MESSAGE TYPE 'MyMessage' (@msg)

Receive_SP(TargetQueue 上激活的 SP)

DECLARE @type SYSNAME, @h UNIQUEIDENTIFIER, @msg XML;
DECLARE @target TABLE (
    [message_type_name] SYSNAME,
    [message_body] VARBINARY(MAX),
    [conversation_handle] UNIQUEIDENTIFIER
)
WHILE(1=1)
BEGIN TRANSACTION
    WAITFOR(RECEIVE TOP (1000) 
        [message_type_name],[message_body],[conversation_handle] 
        FROM TargetQueue INTO @target), TIMEOUT 2000            
    IF(@@rowcount!=0)
    BEGIN
        WHILE((SELECT count(*) FROM @target) > 0) 
        BEGIN
        SELECT TOP (1) @type = [message_type_name],
            @msg = [message_body],
            @h = [conversation_handle]  FROM @target;
        // Handle Message Here
        END CONVERSATION @h; 
        DELETE TOP (1) FROM @target;
    END
END
COMMIT TRANSACTION;

End_SP(在 InitiatorQueue 上激活的 SP)

DECLARE @type SYSNAME, @h UNIQUEIDENTIFIER, @msg XML;
DECLARE @init TABLE (
    [message_type_name] SYSNAME,
    [message_body] VARBINARY(MAX),
    [conversation_handle] UNIQUEIDENTIFIER
)
WHILE(1=1)
BEGIN TRANSACTION
    WAITFOR(RECEIVE TOP (1000) 
        [message_type_name],[message_body],[conversation_handle] 
        FROM InitiatorQueue INTO @init), TIMEOUT 2000           
    IF(@@rowcount!=0)
    BEGIN
        WHILE((SELECT count(*) FROM @init) > 0) 
        BEGIN
        SELECT TOP (1) @type = [message_type_name],
            @msg = [message_body],
            @h = [conversation_handle]  FROM @init;
        END CONVERSATION @h; 
        DELETE TOP (1) FROM @init;
    END
END
COMMIT TRANSACTION;
4

1 回答 1

1

使用即发即弃模式将不可避免地导致此类问题和其他类型的问题。此外,它会使任何假设错误都被忽视。是否有任何理由不能更改消息交换模式,以便目标在收到消息后发出 END CONVERSATION (无需清理!),然后发起者在收到结束对话消息时仅调用 END CONVERSATION (同样,无需清理)从目标?

于 2010-08-11T20:26:58.323 回答