È possibile creare un processo che controlli la tabella msdb.dbo.sysjobhistory ogni minuto (o per quanto frequentemente si desideri). Potresti voler implementare una tabella delle code in modo da poter inviare il messaggio solo per un singolo errore di istanza una sola volta.
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)
);
Quindi il tuo codice, che puoi programmare in un lavoro, diventa:
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
);
Ora suppongo che tu voglia inviare una singola e-mail per ogni errore, quindi anche questo potrebbe far parte del lavoro (o parte di un lavoro diverso, anche se non è necessariamente saggio):
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;
Ci sono anche altre opzioni:
- pull in sysjobhistory.message
- guarda i singoli passaggi che hanno fallito
- inviare un messaggio per qualsiasi lavoro solo una volta in n minuti / ore anche se ci sono più errori
- inviare una singola e-mail con un elenco di tutti i lavori non riusciti, anziché una e-mail per ogni errore
- potresti voler includere run_date e run_time nel messaggio, poiché l'e-mail potrebbe non essere inviata o ricevuta abbastanza rapidamente da essere una misura accurata di quando il lavoro è effettivamente fallito (non l'ho incluso qui perché le loro orribili scelte sul tipo di dati fare della formattazione quella roba una PITA reale)
- probabilmente vorrai ripulire le vecchie righe dopo un po 'di tempo, quindi potrebbe essere desiderato anche un comando di eliminazione
Se Posta elettronica database non è già impostata, consultare questa esercitazione .
È inoltre possibile utilizzare strumenti di terze parti (ad esempio SQL Sentry Event Manager ) che semplificheranno notevolmente questa operazione. Informativa completa: lavoro per SQL Sentry.
AND EXISTS
parte diINSERT/SELECT
. E probabilmente cambi il nomeReportServerJob_FailQueue
in qualcosa di più generico. :-)