Você pode criar um trabalho que verifique a tabela msdb.dbo.sysjobhistory a cada minuto (ou com a frequência que desejar). Você pode implementar uma tabela de filas para enviar apenas a mensagem para qualquer falha de instância única uma vez.
USE msdb;
GO
CREATE TABLE dbo.ReportServerJob_FailQueue
(
job_id UNIQUEIDENTIFIER,
run_date INT,
run_time INT, -- horrible schema, just matching sysjobhistory
sql_message_id INT,
sent BIT NOT NULL DEFAULT 0,
PRIMARY KEY (job_id, run_date, run_time)
);
Portanto, seu código, que você pode agendar em um trabalho, se torna:
INSERT dbo.ReportServerJob_FailQueue
(job_id, run_date, run_time, sql_message_id)
SELECT job_id, run_date, run_time, sql_message_id
FROM msdb.dbo.sysjobhistory AS h
WHERE step_id = 0
AND run_status = 0
AND EXISTS
(
SELECT 1 FROM msdb.dbo.sysjobs AS j
INNER JOIN msdb.dbo.syscategories AS c
ON j.category_id = c.category_id
WHERE j.job_id = h.job_id
AND c.name = 'Report Server'
)
AND NOT EXISTS
(
SELECT 1 FROM dbo.ReportServerJob_FailQueue
WHERE job_id = h.job_id
AND run_date = h.run_date
AND run_time = h.run_time
);
Agora, suponho que você queira enviar um email individual para cada falha, portanto isso também pode fazer parte do trabalho (ou parte de um trabalho diferente, embora isso não seja necessariamente sensato):
DECLARE
@subject NVARCHAR(4000),
@body NVARCHAR(4000),
@name SYSNAME,
@id UNIQUEIDENTIFIER,
@date INT,
@time INT,
@msg INT;
DECLARE c CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR SELECT q.job_id, q.run_date, q.run_time, q.sql_message_id, j.name
FROM dbo.ReportServerJob_FailQueue AS q
INNER JOIN msdb.dbo.sysjobs AS j
ON q.job_id = j.job_id
WHERE q.sent = 0;
OPEN c;
FETCH NEXT FROM c INTO @id, @date, @time, @msg, @name;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @subject = 'Report Server job ' + @name + ' failed.';
SET @body = 'Error number: ' + RTRIM(@msg);
BEGIN TRY
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'default', -- you may need to change this
@recipients = 'foo@bar.com', -- you will need to change this
@subject = @subject,
@body = @body;
UPDATE dbo.ReportServerJob_FailQueue
SET sent = 1
WHERE job_id = @id
AND run_date = @date
AND run_time = @time;
END TRY
BEGIN CATCH
PRINT 'Will have to try that one again later.';
END
FETCH NEXT FROM c INTO @id, @date, @time, @msg, @name;
END
CLOSE c; DEALLOCATE c;
Existem outras opções também:
- pull em sysjobhistory.message
- observe as etapas individuais que falharam
- envie apenas uma mensagem para qualquer trabalho uma vez em n minutos / horas, mesmo se houver várias falhas
- envie um único email com uma lista de todos os trabalhos que falharam, em vez de um email para cada falha
- convém incluir run_date e run_time na mensagem, pois o email pode não ser enviado ou recebido com rapidez suficiente para ser uma medida precisa de quando a tarefa realmente falhou (não a incluí aqui porque suas horríveis opções de tipo de dados tornar a formatação dessas coisas uma PITA real)
- você provavelmente desejará limpar as linhas antigas depois de algum tempo; portanto, um comando de limpeza também pode ser desejado
Se o Database Mail ainda não estiver configurado, consulte este tutorial .
Você também pode usar ferramentas de terceiros (por exemplo, SQL Sentry Event Manager ) que simplificarão muito isso. Divulgação completa: Trabalho para o SQL Sentry.
AND EXISTS
parte doINSERT/SELECT
. E provavelmente mude o nomeReportServerJob_FailQueue
para algo mais genérico. :-)