确认 EndDialog 时启动器从未激活

Posted

技术标签:

【中文标题】确认 EndDialog 时启动器从未激活【英文标题】:Initiator never activated when acknowledged of EndDialog 【发布时间】:2019-12-16 07:44:04 【问题描述】:

我希望在我的 SSB 实现中遵守Remus Rusanu 的对话回收技术。我为发起者队列编写了一些激活过程,以便从目标中挂钩 EndDialog 消息并从关闭的对话句柄中清除 Dialog 表。

尽管如此,虽然 EndDialog ack 正确到达了发起方,但没有触发激活,所以我的消息处理程序无法操作和清理该位置。

CREATE PROCEDURE fdwh.ProcessResponse
AS
BEGIN
    DECLARE @dlgId UNIQUEIDENTIFIER;
    DECLARE @msgTypeName SYSNAME;
    DECLARE @msgBody VARBINARY(MAX);
    DECLARE @payloadHistoryId   INT;

    BEGIN TRY
        BEGIN TRANSACTION

        WAITFOR(
            RECEIVE TOP(1)
                @dlgId = [conversation_handle],
                @msgTypeName = message_type_name,
                @msgBody = message_body
            FROM [fdwh].[SenderQueue]), TIMEOUT 10;

        -- Message is regular end of conversation, terminate it
        IF (@msgTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
        BEGIN
            END CONVERSATION @dlgId;

            DELETE FROM DWH_BOARD.dbo.Dialog
            WHERE (DbId = DB_ID()) AND
                  (DialogId = @dlgId);
        END

        -- Message is error, extracts and logs number and description
        IF (@msgTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
        BEGIN
[...]

我希望触发队列激活并处理http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog 消息,但事实并非如此。 EndDialog ACK 不是普通消息吗?

请在下面找到自我解释的 Profiler 跟踪屏幕截图:。

示例是纯本地的(单个实例/两个 DB)。

谢谢,

更新 失败队列的更多指标: `SELECT que.[name], que.is_activation_enabled, que.is_receive_enabled, que.is_poison_message_handling_enabled, que.activation_procedure, que.max_readers, [execute_as] = (SELECT pri.[name] FROM sys.database_principals pri WHERE pri.principal_id = que .execute_as_principal_id) FROM sys.service_queues que WHERE que.[name] = 'SenderQueue'; 去吧

SELECT conversation_handle、to_service_name、message_type_name、is_conversation_error、is_end_of_dialog、enqueue_time、transmission_status FROM sys.transmission_queue; 去吧

SELECT [name], is_broker_enabled, log_reuse_wait_desc FROM sys.databases WHERE database_id = 8; 去吧

EXEC sp_spaceused 'fdwh.SenderQueue'; 去吧

SELECT * FROM sys.dm_broker_activated_tasks WHERE database_id=8; 去吧

SELECT [state], last_activated_time, tasks_waiting FROM sys.dm_broker_queue_monitors WHERE database_id = 8; 走 `

【问题讨论】:

检查 SQL Server 错误日志以获取与激活错误相关的消息。 谢谢@DanGuzman。错误日志中没有任何有价值的东西。顺便说一句,在所有其他情况下(出站错误消息、自定义 ping 实现),我的激活存储过程都被激活了。我看了一下 Remuses 的一些线程,它处理激活故障排除,但没有运气。我可以提供有关我的“有罪”队列的其他指标。 忘了告诉我,我还运行了 xevent 监视会话,范围限定为队列激活事件,并且没有为 EndDialog 情况挂钩任何事件,而其他情况下一切正常。 【参考方案1】:

只有在新消息到达时才会激活。

"当STATUS = ON时,队列启动指定的存储过程 当当前运行的过程数为 小于 MAX_QUEUE_READERS 并且消息到达队列时 比存储过程接收消息要快。”

https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-queue-transact-sql?view=sql-server-2017

预计激活过程将继续使用消息,直到队列为空,并在其 WATFOR ... RECEIVE 期间保持为空。

您的激活过程缺少循环。它正在接收一条消息并退出。因此,每次新消息到达时,都会消耗一条旧消息。这可能似乎可以工作一段时间,但如果您收到积压的消息,您将永远赶不上。

【讨论】:

你好@david-browne-microsoft。感谢您的宝贵反馈。实际上,我的激活过程存在泄漏,与连续返回多条消息的过程有关。我会解决这个问题。尽管如此,这不是我将此线程标记为已解决的原因。我注意到到目前为止我还没有意识到我意外地进行了即发即弃的消息传递:( 结束对话必须由目标或发起者发起在响应来自目标的传入错误通知时。从一开始就不要来自发起者,除非激活永远不会触发。

以上是关于确认 EndDialog 时启动器从未激活的主要内容,如果未能解决你的问题,请参考以下文章

Windows进程激活服务错误2:系统找不到指定的文件

Eclipse 启动异常时激活 Eclipse 插件

Durandal js,所有功能在启动时激活

在 MFC 中调用 EndDialog() 时,类析构函数何时触发?

首次启动后 SwiftUI 工作表从未更新

如何在启动时在 Armbian 上激活虚拟环境?