您可以创建一个每分钟检查一次msdb.dbo.sysjobhistory表的作业(或根据需要进行一次检查)。您可能想要实现一个队列表,因此对于任何单个实例故障,您一次只能发送一次消息。
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)
);
因此,您可以在工作中安排的代码将变为:
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
);
现在,我假设您想为每次失败发送一封单独的电子邮件,因此这也可能是工作的一部分(或者是其他工作的一部分,尽管不一定明智):
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;
还有其他一些选择:
- 拉入sysjobhistory.message
- 查看失败的各个步骤
- 即使有多个失败,也仅在n分钟/小时内为任何作业发送一次消息
- 发送一封包含所有失败作业列表的电子邮件,而不是每次失败的电子邮件
- 您可能希望在消息中包含run_date和run_time,因为电子邮件发送或接收的速度可能不够快,无法准确地衡量作业实际何时失败(我在此处未添加电子邮件,因为他们选择了糟糕的数据类型将格式设置为皇家PITA)
- 您可能需要在一段时间后清理旧行,因此也可能需要使用清除命令
如果尚未设置数据库邮件,请参阅本教程。
您也可以使用第三方工具(例如SQL Sentry Event Manager),这将使很多事情变得更加简单。全面披露:我为SQL Sentry工作。
AND EXISTS
部分INSERT/SELECT
。并且可能将名称更改为ReportServerJob_FailQueue
更通用的名称。:-)