Foi feito backup do broker do serviço, agora recebendo, mas não parece estar processando


20

Tendo um problema com as Notificações de Eventos. Na máquina / unidade / banco de dados para o qual as mensagens são enviadas (receptor), a unidade é preenchida quando ninguém está olhando, por isso é copiada o dia inteiro.

Agora que liberamos espaço na unidade, ele está aceitando mensagens na fila, mas parece não estar processando-as - nenhum novo registro foi inserido, mesmo que a fila agora tenha 22 milhões de mensagens e cresça (!). A fila está habilitada:

is_activation_enabled = 1
is_receive_enabled = 1
is_enqueue_enabled = 1

Vejo o SP ativado activation_procedure, mas quando olho para dentro SP_WHOISACTIVE, não vejo nenhum leitor ativo.

Antes de desligar novamente a unidade - o que estou fazendo de errado? Como faço para processar ou liberar as mensagens? Desde já, obrigado.

Atualizar

Um pensamento - desde que eu tenho is_enqueue_enabled, talvez esteja armazenando todas as mensagens até que possa processar todas elas? Nesse caso, posso desativar isso com segurança?

CREATE PROCEDURE [dbo].[Parse_EN_Messages]
AS
--mdb 2012/09/05 version 1.2  
-- With apologies and thanks to Remus Rusanu, Jonathon Kehayias, Mladen Prajdic, and Jasper Smith for writing
-- about EN, answering questions, and getting the word out about this awesome feature of SQL Server 2005+.
-- Also thanks to Mikael Eriksson for a faster parse with the XML filter.
-- Their code modified, combined, and used below.  Any errors herein are mine, not theirs.  
-- Part of the code came from MVP Deep Dives Vol 1 Chapter 28 (Mladen), PASS Presentations by Jasper and Jonathon,
-- and Stackexchange (below) from Remus and Mikael Eriksson
-- http://dba.stackexchange.com/questions/10273/how-to-create-an-event-notification-that-runs-a-job-procedure-when-mirroring-sta
-- http://stackoverflow.com/questions/12308099/t-sql-dynamically-filter-xml-on-multiple-conditions/12358926
--History:  1.00 2012/08/27 first release
--          1.01 2012/09/05 added server-based exclusions and eventsubclass = 0
--          1.1  2012/09/17 added exclusion_sets which allow multi-condition filtering and improved performance
--          1.11 2012/10/05 removing the 1=1 as per suggestion by Rusanu; 
--                              this could cause it to spin forever, blowing out the error_log..and the drive.
--          1.12 2012/11/14 adding a RETURN in the @@ROWCOUNT. It fails to exit and then hits a COMMIT, causing records
--                              in enaudit_error.  That was due to the 1.11 change where I no longer use a 1=1.
--          1.13 2014/01/16 changing ERRORLOG to write the first 500 chars to the CommandText field, as tested in Canada.

SET NOCOUNT ON 
DECLARE @message_type NVARCHAR(256),
@message VARBINARY(MAX),
@conversation_handle UNIQUEIDENTIFIER,
@auditdata XML,
@queuing_order BIGINT,
@conversation_group_id UNIQUEIDENTIFIER

BEGIN
    BEGIN TRANSACTION;
    BEGIN TRY;
    WAITFOR (
        RECEIVE TOP(1)
        @conversation_handle = [conversation_handle], --aka dialog
        @conversation_group_id = [conversation_group_id],
        @message_type = message_type_name,
        @message = message_body, 
        @queuing_order = queuing_order
        FROM dbo.ENAudit_SBQueue --ORDER BY queuing_order --order by doesn't work there.
        ), TIMEOUT 5000 --we need the timeout so that it won't hold transactions open indefinitely.

    IF (@@ROWCOUNT = 0)
    BEGIN
        ROLLBACK TRANSACTION
  --mdb 1.12 2012/11/14 adding a return as otherwise it tries to commit later and fails, causing records in enaudit_error      
        RETURN 
    END

    SELECT @auditdata = CAST(@message AS XML)

    IF @message_type = N'http://schemas.microsoft.com/SQL/Notifications/EventNotification'
    -- Dynamically shred the XML and compare to our exclusion table.  You should be able to filter on any field.
    -- Exclusion set: unique char(2) name. Has to match every condition.  Servername is one of the fields handled.
    -- Be careful as the filters could impact performance.
    and NOT EXISTS --if all active members of the same exclusion_set match, the event is excluded.
    (
    SELECT * FROM 
    (
    select COUNT(*) AS match_count, exclusion_set
                  from enaudit_exclusion_list 
                  where exists (
                               select *
                               from (
                                    select X.N.value('local-name(.)', 'varchar(128)') as NodeName,
                                           X.N.value('./text()[1]', 'varchar(max)') as NodeValue
                                    from @auditdata.nodes('//*') as X(N)
                                    ) T
                               where T.NodeName = enaudit_exclusion_list.exclusion_type and
                                     T.NodeValue like enaudit_exclusion_list.excluded_value 
                                     AND  enaudit_exclusion_list.active = 1
                               )
    GROUP BY exclusion_set
    ) matches_per_set
    INNER JOIN 
    (SELECT COUNT(*) AS total_count, exclusion_set FROM enaudit_exclusion_list WHERE active = 1 GROUP BY exclusion_set) grouped_set
    ON match_count = total_count
    AND grouped_set.exclusion_set = matches_per_set.exclusion_set
    )
    BEGIN
    INSERT INTO ENAudit_Events
            ( ServerName ,
                queuing_order ,
                PostTime ,
                StartTime,
                EventType ,
                SPID ,
                LoginName ,
                UserName ,
                DatabaseName ,
                SchemaName ,
                ObjectName ,
                ObjectType ,
                TargetObjectName ,
                TargetObjectType ,
                CommandText ,
                insert_datetime,
                message_body_xml
            )
--over 128 elements exist, I've chosen the most useful for what I'm doing.
--To get a full list, GROUP BY in the XSD from http://schemas.microsoft.com/sqlserver/2006/11/eventdata/events.xsd
-- More information in EVENTDATA http://msdn.microsoft.com/en-us/library/ms187909.aspx
    SELECT 
        @auditdata.value('(/EVENT_INSTANCE/ServerName)[1]', 'varchar(128)' ) AS ServerName,
        @queuing_order AS Queuing_Order, 
        @auditdata.value('(/EVENT_INSTANCE/PostTime)[1]', 'datetime') AS PostTime,
        @auditdata.value('(/EVENT_INSTANCE/StartTime)[1]', 'datetime') AS StartTime,
        @auditdata.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)' ) as EventType,
        @auditdata.value('(/EVENT_INSTANCE/SPID)[1]', 'bigint') AS SPID,
        @auditdata.value('(/EVENT_INSTANCE/LoginName)[1]', 'varchar(128)' ) AS LoginName,
        @auditdata.value('(/EVENT_INSTANCE/UserName)[1]', 'varchar(128)' ) AS UserName,
        @auditdata.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(128)' ) AS DatabaseName,
        @auditdata.value('(/EVENT_INSTANCE/SchemaName)[1]', 'varchar(128)' ) AS SchemaName,
        @auditdata.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(128)' ) AS ObjectName,
        @auditdata.value('(/EVENT_INSTANCE/ObjectType)[1]', 'varchar(128)' ) AS ObjectType,
        @auditdata.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'varchar(128)' ) AS TargetObjectName,
        @auditdata.value('(/EVENT_INSTANCE/TargetObjectType)[1]', 'varchar(128)' ) AS TargetObjectType,
        --@auditdata.value('(/EVENT_INSTANCE/PropertyName)[1]', 'varchar(128)' ) AS PropertyName,
        --@auditdata.value('(/EVENT_INSTANCE/PropertyValue)[1]', 'varchar(128)' ) AS PropertyValue,
        --@auditdata.value('(/EVENT_INSTANCE/Parameters)[1]', 'varchar(128)' ) AS Parameters,
        CASE @auditdata.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)' )
        WHEN 'ERRORLOG' THEN @auditdata.value('/EVENT_INSTANCE[1]/TextData[1]', 'varchar(500)')
        ELSE @auditdata.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'varchar(max)' ) END AS CommandText,
        GETDATE(),
        @auditdata 
    --Other possibilities for doing a dynamic XML query?
    --      http://www.dotnetgenerics.com/Modules/TricksAndTips/SQLServer/DynamicWhereClause.aspx
    --      http://www.beefycode.com/post/Expressing-Filter-Queries-as-XML-in-SQL-Server.aspx
    --      http://stackoverflow.com/questions/923136/t-sql-filtering-on-dynamic-name-value-pairs
    --      http://stackoverflow.com/questions/1729973/filter-sql-queries-on-the-xml-column-using-xpath-xquery
    END         
    else 
    IF @message_type = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error' --log error messages
    BEGIN 
        WITH XMLNAMESPACES ('http://schemas.microsoft.com/SQL/ServiceBroker/Error' AS ssb)
        INSERT INTO ENAudit_Errors ([conversation_group_id], [conversation_handle], 
        [queuing_order], error_code, error_description, insert_datetime, message_body_raw)
        SELECT @conversation_group_id, @conversation_handle, @queuing_order,
                @auditdata.value('(//ssb:Error/ssb:Code)[1]', 'INT') AS error_code,
                @auditdata.value('(//ssb:Error/ssb:Description)[1]', 'NVARCHAR(4000)') AS error_description,
                GETDATE(), 
                @message

         end conversation @conversation_handle --close the conversation if there was an error
    END
    ELSE 
    IF @message_type =  N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
        begin
            end conversation @conversation_handle;
        end
    COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
    declare @xact_state int = xact_state(), 
            @error_number int = error_number(), 
            @error_message nvarchar(4000) = error_message(),
            @has_rolled_back bit = 0;
        if @xact_state = -1
        begin
            -- Doomed transaction, it must rollback
            rollback;
            set @has_rolled_back = 1;
        end
        else if @xact_state = 0
        begin
            -- transaction was already rolled back (deadlock?)
            set @has_rolled_back = 1;
        end
        insert INTO ENAudit_Errors(
            insert_datetime,
            error_code,
            error_description,
            message_body_raw)
        values (
            getdate(),
            @error_number,
            @error_message,
            @message);
        if (@has_rolled_back = 0)
        begin
            commit;
        end
    end catch
 END




GO

11
Portanto, na descrição do seu problema, você está usando a ativação interna. Existe algo listado em sys.dm_broker_activated_tasks? Como é o seu procedimento de ativação? Você pode publicá-lo aqui? Pode ser que o procedimento esteja tentando processar todas as mensagens de uma só vez (ou seja, em uma transação), o que pode ser ruim. Além disso, não há nada que impeça você de executar a ativação manualmente.
precisa

2
A fila provavelmente está desabilitada devido a uma mensagem suspeita (muitas falhas). Consulte sys.transmission_queue e informe-nos quais erros estão relatando. Se minha suspeita estiver correta, tente reiniciar a fila usando uma instrução ALTER QUEUE.
Robert L Davis

3
@BenThul adicionou o código do Procedimento armazenado ativado à pergunta. FWIW, eu não uso 1 = 1. Conversei com Remus Rusanu sobre isso há alguns anos, e ele falou sobre como não há razão para usá-lo, e modifiquei o meu de acordo. Dito isto, eu provavelmente deveria procurar alterá-lo para executar lotes de 100/1000, para obter velocidade. Mas até o backup, ele estava funcionando como um campeão, então eu detestava tocá-lo.
mbourgon

2
Discordo que o loop é desnecessário exatamente para a situação em que você está agora. De acordo com este artigo da BOL ( technet.microsoft.com/en-us/library/… ), a ativação provavelmente não está sendo acionada com frequência suficiente. É por isso que, quando é acionado, você deseja que cada procedimento continue processando mensagens até que não haja mais o que processar. Apenas meus dois centavos. Para sair do buraco em que está agora, você pode fazer algo como while exists (select 1 from dbo.ENAudit_SBQueue) begin exec [dbo].[Parse_EN_Messages]; endno SSMS para fingir.
Ben Thul

6
Ter um olhar rusanu.com/2008/08/03/understanding-queue-monitors e ver se ele se aplica
Remus Rusanu

Respostas:


2

Para os pontos de extremidade tcp, de ambos os lados, considere a conta de serviço usada e a permissão de conexão - tente conceder novamente e inicie novamente os pontos de extremidade -> mesmo que gui ou dmv digam que foram iniciados.


Um pouco mais de detalhes provavelmente poderia ajudar o pôster original.
joanolo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.