Service Broker messages start to get hung up after about a day

爱⌒轻易说出口 提交于 2019-12-04 07:36:00

I have found an acceptable approach to solving this issue. First, I migrated my code away from SqlDependency and I am now using SqlNotificationRequest instead. Doing this prevents Broker Queues and Services from being created/destroyed at unexpected times.

Even with this however, when my application exits there are still a few conversations that don't get marked as closed because the original endpoint that setup the notification is no longer there. Therefore, each time my server re-initializes my code I am clearing out existing conversations.

This adjustment has reduced the number of connections that I have on a daily bases from over 1000 and having to manually kill them, to having a max of about 20 at all times. I highly recommend using SqlNotificationRequest instead of SqlDependency.

I have found a way to clear out the conversations that are stuck. I retrieve all of the generated SqlDependency queues that still exist and iterate over the conversations that don't belong to any of these and end those conversations. Below is the code:

SET NOCOUNT OFF;
DECLARE @handle UniqueIdentifier
DECLARE @count INT = 0

-- Retrieve orphaned conversation handles that belong to auto-generated SqlDependency queues and iterate over each of them
DECLARE handleCursor CURSOR
FOR 
SELECT [conversation_handle]
FROM sys.conversation_endpoints WITH(NOLOCK)
WHERE
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS like 'SqlQueryNotificationService-%' COLLATE SQL_Latin1_General_CP1_CI_AS AND
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS NOT IN (SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS FROM sys.service_queues)

DECLARE @Rows INT
SELECT @Rows = COUNT(*) FROM sys.conversation_endpoints WITH(NOLOCK)
WHERE
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS like 'SqlQueryNotificationService-%' COLLATE SQL_Latin1_General_CP1_CI_AS AND
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS NOT IN (SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS FROM sys.service_queues)

WHILE @ROWS>0
BEGIN
    OPEN handleCursor

    FETCH NEXT FROM handleCursor 
    INTO @handle

    BEGIN TRANSACTION

    WHILE @@FETCH_STATUS = 0
    BEGIN

        -- End the conversation and clean up any remaining references to it
        END CONVERSATION @handle WITH CLEANUP

        -- Move to the next item
        FETCH NEXT FROM handleCursor INTO @handle
        SET @count= @count+1
    END

    COMMIT TRANSACTION
    print @count

    CLOSE handleCursor;

    IF @count > 100000
    BEGIN
        BREAK;
    END

    SELECT @Rows = COUNT(*) FROM sys.conversation_endpoints WITH(NOLOCK)
    WHERE
        far_service COLLATE SQL_Latin1_General_CP1_CI_AS like 'SqlQueryNotificationService-%' COLLATE SQL_Latin1_General_CP1_CI_AS AND
        far_service COLLATE SQL_Latin1_General_CP1_CI_AS NOT IN (SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS FROM sys.service_queues)
END
DEALLOCATE handleCursor;

Started Outbound means 'SQL Server processed a BEGIN CONVERSATION for this conversation, but no messages have yet been sent.' (from Books Online) It looks like you are creating conversations that are not then being used, so they never get closed.

Not entirely sure why that would be causing a degradation in performance though.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!