Pergunta

Posso (como faço) configurar o SQL Server 2008 para notificar um operador se alguma etapa no trabalho falhar?

Eu tenho um trabalho de SQL Server com várias etapas para atualizar dados de várias fontes diferentes, seguido por uma etapa final que executa vários cálculos nos dados. Todas as etapas de "atualização de dados" estão definidas como "Vá para a próxima etapa na falha". De um modo geral, se uma das atualizações de dados falhar, eu ainda quero a etapa final para executar, mas ainda quero ser notificado sobre as falhas intermediárias; portanto, se elas falharem de forma consistente, posso investigar.

Foi útil?

Solução

Aqui está como fazemos isso. Adicionamos uma última etapa T-SQL (geralmente chamada de "etapas de verificação") com isso

SELECT  step_name, message
FROM    msdb.dbo.sysjobhistory
WHERE   instance_id > COALESCE((SELECT MAX(instance_id) FROM msdb.dbo.sysjobhistory
                                WHERE job_id = $(ESCAPE_SQUOTE(JOBID)) AND step_id = 0), 0)
        AND job_id = $(ESCAPE_SQUOTE(JOBID))
        AND run_status <> 1 -- success

IF      @@ROWCOUNT <> 0
        RAISERROR('Ooops', 16, 1)

Observe que este código está usando Tokens em etapas de trabalho (a $(...) parte), portanto, o código não pode ser executado no SSMS como está. Ele tenta básico encontrar entradas de etapas anteriores do trabalho atual em sysjobhistory e procura status de falha.

Em propriedades-> avançado, você também pode verificar Inclua saída de etapa na história Para obter a mensagem da falha da etapa. Deixe o Na ação de falha para Saia da falha do relatório de emprego.

Outras dicas

A resposta aceita pelo @WQW é excelente.

Eu o estendi para quem possui correio de banco de dados ativado para enviar um pouco mais de detalhes sobre exatamente o que falhou e como. Também incorpora a resposta do ICVADER nesta página para levar em consideração as tentativas.

Deve ser realmente útil para aqueles de nós que precisam de mais detalhes para julgar se a ação urgente é necessária quando está fora do local/de plantão.

DECLARE 

@YourRecipients as varchar(1000) = 'myadminemail@bloatcorp.com'
,@YourMailProfileName as varchar(255) = 'Database Mail'

,@Msg as varchar(1000)
,@NumofFails as smallint
,@JobName as varchar(1000)
,@Subj as varchar(1000)
,@i as smallint = 1


---------------Fetch List of Step Errors------------
SELECT *
INTO #Errs

FROM

    (
    SELECT 
      rank() over (PARTITION BY step_id ORDER BY step_id) rn
    , ROW_NUMBER() over (partition by step_id order by run_date desc, run_time desc) ReverseTryOrder
    ,j.name job_name
    ,run_status
    , step_id
    , step_name
    , [message]

    FROM    msdb.dbo.sysjobhistory h
    join msdb.dbo.sysjobs j on j.job_id = h.job_id

    WHERE   instance_id > COALESCE((SELECT MAX(instance_id) FROM msdb.dbo.sysjobhistory
                                    WHERE job_id = $(ESCAPE_SQUOTE(JOBID)) AND step_id = 0), 0)
            AND h.job_id = $(ESCAPE_SQUOTE(JOBID))
    ) as agg

WHERE ReverseTryOrder = 1 ---Pick the last retry attempt of each step
  AND run_status <> 1 -- show only those that didn't succeed 


SET @NumofFails = ISNULL(@@ROWCOUNT,0)---Stored here because we'll still need the rowcount after it's reset.


-------------------------If there are any failures assemble email and send ------------------------------------------------
IF  @NumofFails <> 0
    BEGIN

        DECLARE @PluralS as char(1) = CASE WHEN @NumofFails > 1 THEN 's' ELSE '' END ---To make it look like a computer knows English
        SELECT top 1 @Subj = 'Job: ' + job_name + ' had ' + CAST(@NumofFails as varchar(3)) + ' step' + @PluralS + ' that failed'
                    ,@Msg =  'The trouble is... ' +CHAR(13) + CHAR(10)+CHAR(13) + CHAR(10)

                        FROM dbo.#Errs


        WHILE @i <= @NumofFails 
        BEGIN
            SELECT @Msg = @Msg + 'Step:' + CAST(step_id as varchar(3)) + ': ' + step_name  +CHAR(13) + CHAR(10)

            + [message] +CHAR(13) + CHAR(10)+CHAR(13) + CHAR(10) FROM dbo.#Errs
            WHERE rn = @i


            SET @i = @i + 1
        END

            exec msdb.dbo.sp_send_dbmail
            @recipients = @YourRecipients,
            @subject = @Subj,
            @profile_name = @YourMailProfileName,
            @body = @Msg


    END

Uma diferença das outras respostas nas quais se baseia: não levanta todo o trabalho como um erro. Isso é para manter a distinção no histórico do trabalho entre abortado e concluído com erros.

Uma melhoria na resposta acima, caso alguém queira usar os operadores no agente do SQL Server para enviar email; e use o nome do perfil do banco de dados armazenado no msdb:

DECLARE @EmailRecipients as varchar(1000)
DECLARE @MailProfileName as varchar(255)
DECLARE @Msg as varchar(1000)
DECLARE @NumofFails as smallint
DECLARE @JobName as varchar(1000)
DECLARE @Subj as varchar(1000)
DECLARE @i as smallint = 1

SELECT @EmailRecipients = email_address 
FROM msdb.dbo.sysoperators
WHERE name = <Operator Name>

SELECT TOP(1) @MailProfileName = name 
FROM msdb.dbo.sysmail_profile

SELECT * INTO #Errs
FROM
    (SELECT rank() over (PARTITION BY step_id ORDER BY step_id) rn, 
            ROW_NUMBER() over (partition by step_id order by run_date desc, run_time desc) ReverseTryOrder,
           j.name job_name,
           run_status,
           step_id,
           step_name,
           [message]
     FROM msdb.dbo.sysjobhistory h
     JOIN msdb.dbo.sysjobs j ON j.job_id = h.job_id
     WHERE instance_id > COALESCE((SELECT MAX(instance_id) FROM msdb.dbo.sysjobhistory
                                    WHERE job_id = $(ESCAPE_SQUOTE(JOBID)) AND step_id = 0), 0)
     AND h.job_id = $(ESCAPE_SQUOTE(JOBID))
    ) AS agg
WHERE ReverseTryOrder = 1 ---Pick the last retry attempt of each step
AND run_status <> 1 -- show only those that didn't succeed 


SET @NumofFails = ISNULL(@@ROWCOUNT,0)---Stored here because we'll still need the rowcount after it's reset.

IF  @NumofFails <> 0
BEGIN
    DECLARE @PluralS as char(1) = CASE WHEN @NumofFails > 1 THEN 's' ELSE '' END

    SELECT top 1 @Subj = job_name + ':'+ CAST(@NumofFails as varchar(3)) + '''Check Steps'' Report',
                 @Msg =  '''Check Steps'' has reported that one or more Steps failed during execution of ' + job_name + CHAR(13) + CHAR(10)+ CHAR(13) + CHAR(10)
    FROM dbo.#Errs

    WHILE @i <= @NumofFails 
    BEGIN
        SELECT @Msg = @Msg + 'Step ' + CAST(step_id as varchar(3)) + ': ' + step_name  +CHAR(13) + CHAR(10)
                     + [message] +CHAR(13) + CHAR(10)+CHAR(13) + CHAR(10) 
        FROM dbo.#Errs
        WHERE rn = @i

        SET @i = @i + 1
    END

    EXEC msdb.dbo.sp_send_dbmail
    @recipients = @EmailRecipients,
    @subject = @Subj,
    @profile_name = @MailProfileName,
    @body = @Msg
END

Eu tenho a maioria das minhas etapas definidas para tentar novamente devido a um cenário de translog exclusivo que causa bloqueio ocasional. A postagem da WQW alertará mesmo que uma etapa tenha se refletido com sucesso. Eu fiz uma adaptação que não alertará se uma etapa falhar, mas depois foi um sucesso na tentativa.

SELECT  step_id, MIN(run_status)
FROM    msdb.dbo.sysjobhistory
WHERE   instance_id > COALESCE((SELECT MAX(instance_id) FROM msdb.dbo.sysjobhistory
                                WHERE job_id = $(ESCAPE_SQUOTE(JOBID)) AND step_id = 0), 0)
        AND job_id = $(ESCAPE_SQUOTE(JOBID))
GROUP BY step_id
HAVING MIN(run_status) <> 1 -- success

IF @@ROWCOUNT <> 0
RAISERROR('FailedStep', 16, 1)

A resposta de Adamantish é a solução perfeita (obrigado): funcionou perfeitamente .. edições menores. Como a WQW declarou antes, não funcionará no SSMS, adicione isso como uma última etapa e execute o trabalho.

WHERE instance_id > COALESCE
(
(
SELECT MAX(instance_id) 
FROM msdb.dbo.sysjobhistory
WHERE job_id = '2XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX' AND step_id = 0), 0
)
AND h.job_id = '2XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX'
) 
as agg

Vá para as propriedades do trabalho> Guia de notificação> Ação para executar quando o trabalho concluir

Sob essa verificação da caixa de seleção e selecione "Quando o trabalho falhar" no suspensão e salve o trabalho.

Leia o 4º ponto em http://msdn.microsoft.com/en-us/library/ms191130.aspx

Se você deseja notificar um operador por e-mail, verifique e-mail, selecione um operador na lista e selecione um dos seguintes:

  • Quando o trabalho for bem -sucedido: notificar o operador quando o trabalho é concluído com êxito.

  • Quando o trabalho falhar: notificar o operador quando o trabalho é concluído sem sucesso.

  • Quando o trabalho concluir: notificar o operador, independentemente do status de conclusão.

Em cada etapa, adicione código:

if @@error > 0
EXEC sp_send_dbmail @profile_name='DBATeam',
@recipients=dbadmin@somewhere.com',
@subject='SomeJob SomeStep failed',
@body='This is the body of SomeJob SomeStep failed' 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top