Este dilema se puede abordar de diferentes maneras, por lo tanto te enseñamos la solución más completa para nosotros.
Solución:
Puede crear un trabajo que verifique la tabla msdb.dbo.sysjobhistory cada minuto (o con la frecuencia que desee). Es posible que desee implementar una tabla de cola para que solo envíe el mensaje para cualquier falla de instancia única una 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)
);
Entonces, su código, que puede programar en un trabajo, se convierte en:
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
);
Ahora asumo que desea enviar un correo electrónico individual para cada falla, por lo que esto también podría ser parte del trabajo (o parte de un trabajo diferente, aunque eso no es necesariamente inteligente):
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 = '[email protected]', -- 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;
Hay algunas otras opciones también:
- extraer sysjobhistory.message
- mira los pasos individuales que fallaron
- solo envíe un mensaje para cualquier trabajo una vez cada n minutos/horas, incluso si hay múltiples fallas
- enviar un solo correo electrónico con una lista de todos los trabajos que han fallado, en lugar de un correo electrónico por cada falla
- es posible que desee incluir run_date y run_time en el mensaje, ya que es posible que el correo electrónico no se envíe o reciba lo suficientemente rápido como para ser una medida precisa de cuándo falló realmente el trabajo (no lo incluí aquí porque sus horribles opciones de tipo de datos hacer que formatear esas cosas sea un PITA real)
- probablemente querrá limpiar las filas antiguas después de un tiempo, por lo que también se puede desear un comando de purga
Si el correo electrónico de la base de datos aún no está configurado, consulte este tutorial.
También puede usar herramientas de terceros (por ejemplo, SQL Sentry) que simplificarán mucho este proceso. Divulgación completa: trabajo para SQL Sentry.