Недавно я услышал от клиента вопрос, можно ли добавить уведомления о сбоях для заданий агента SQL Server, выполняемых в среде компании. Как вы, вероятно, догадываетесь, в среде обычной компании может существовать множество заданий.

В статье «Сценарий для настройки Database Mail» (опубликована в Windows IT Pro/RE № 2 за 2014 год) я показал, как составить сценарий для настройки компонента Database Mail для SQL Server 2005 и более новых версий. Для этой задачи я сначала воспользовался данным сценарием, а затем ввел дополнительные шаги, чтобы добавить уведомления ко всем заданиям на сервере.

После того, как Database Mail будет настроен, можно подключиться к объекту JobServer сервера, в котором размещаются задания агента SQL Server.

# SQL 2005 and up
$js = $svr.JobServer

Для всех заданий агента необходимо назначить тип уведомления для использования компонента Database Mail. Поэтому настраиваем свойство AgentMailType сервера заданий на использование Database Mail.

$js.AgentMailType = [Microsoft.SqlServer.Management.Smo.Agent.AgentMailType]::DatabaseMail
$js.DatabaseMailProfile = 'DBAAlertsMail'
$js.Alter()

Кроме того, необходим оператор, который будет получать уведомления. Создаем нового оператора и устанавливаем свойство адреса электронной почты.

$oper = New-Object Microsoft.SqlServer.Management.Smo.Agent.Operator ($js, 'DBAAlerts')
$oper.EmailAddress = 'DBAAlerts@example.com'
$oper.Create()

Теперь достаточно пройти по заданиям и настроить передачу уведомлений о сбоях новым операторам. Сервер заданий располагает коллекцией заданий, а свойство Count сообщает, как много заданий имеется в наличии. Вы перебираете задания одно за другим, указываете в свойстве OperatorToEmail имя оператора, свойству EmailLevel назначаете действие OnFailure и изменяете задание.

for ($i=0; $i -lt $js.Jobs.Count; $i++) {
$job = $js.Jobs[$i]
$job.OperatorToEmail = $oper.Name
$job.EmailLevel = [Microsoft.SqlServer.Management.SMO.Agent.CompletionAction]::OnFailure
$job.Alter()
}

В SQL Server 2005 и более новых версиях это все, что нужно сделать. Однако существует множество компаний, до сих пор работающих с SQL Server 2000, и клиент, задавший вопрос, не был исключением. В этой версии Microsoft предоставила компонент SQL Mail, но для него необходимо установить на сервере клиент MAPI, что связано с некоторым риском для безопасности. Герт Дрейперс, в прошлом эксперт Microsoft, подготовил собственный почтовый компонент SMTP, именуемый xp_smtp_sendmail (по его словам, этот компонент проектировался для включения в состав продукта, но тогдашнее руководство решило иначе). Впоследствии Дрейперс выпустил его самостоятельно, распространяя через свой старый веб-сайт.

Я пытался (безуспешно, впрочем) найти надежный источник этого незаменимого инструмента, но в моем архиве нашлась копия программы. Процедура установки состоит в копировании библиотеки DLL в каталог BINN программы SQL Server и регистрации расширенной хранимой процедуры.

Когда это будет сделано, необходимо изменить задания для уведомления о сбоях. Я не мог задействовать встроенную функцию уведомления, поэтому метод, использованный с Database Mail, непригоден. Все задания этой компании состоят из единственного шага, поэтому я решил добавить новый шаг к каждому заданию, присваивая существующему шагу значение succeed, если он завершается успешно, и переходя к новому шагу, FailNotify, если на первом шаге происходит сбой. Затем я добавил шаг FailNotify, чтобы отправить почтовое сообщение с использованием расширенной хранимой процедуры Герта.

Сначала подключитесь к серверу и назначьте переменной $js значение объекта JobServer сервера.

# For SQL 2000
$svr = New-Object Microsoft.SqlServer.Management.Smo.Server MyServer
$js = $svr.JobServer

Пройдите по заданиям. Для каждого задания нужно получить имя задания для темы и текста почтового сообщения.

for ($i=0; $i -lt $js.Jobs.Count; $i++) {
$job = $js.Jobs[$i]
$jnm = $job.Name

Затем создаются инструкции T-SQL, чтобы настроить переменные темы и сообщения, после чего вызывается xp_smtp_sendmail с нужными параметрами. Используйте here-string, чтобы облегчить читаемость.

$cmd = @«
DECLARE @subj varchar(100)
DECLARE @mesg varchar(2000)
select @subj = @@servername + ' — $jnm Failure'
select @mesg = 'The $jnm job on ' + @@servername + ' failed at ' + convert(varchar(25), getdate(), 100)
exec master.dbo.xp_smtp_sendmail
@FROM = N'DBAAlerts@example.com',
@FROM_NAME = N'DBAAlerts',
@TO = N'DBAAlerts@example.com',
@priority = N'NORMAL',
@subject = @subj,
@message = @mesg,
@type = N'text/plain',
@server = N'smtpsrv.example.com'
»@

Необходим счетчик шагов задания. Используйте значение счетчика, уменьшенное на единицу, в качестве указателя на последний шаг в задании. А пока передайте объект JobStep в переменную $jst.

$jsc = $job.JobSteps.Count
$jsu = $jsc — 1
$jst = $job.JobSteps[$jsu]

Создайте новый шаг с именем FailNotify, используя подсистему TransactSql, и назначьте подготовленную ранее команду T-SQL в качестве команды для этого шага.

$jsn = new-object ('Microsoft.SqlServer.Management.Smo.Agent.JobStep') ($job, 'FailNotify')
$jsn.SubSystem = 'TransactSql'
$jsn.Command = $cmd

Поскольку это шаг сбоя, как OnSuccessAction, так и OnFailAction устанавливаются в значение QuitWithFailure, и создается шаг в задании.

$jsn.OnSuccessAction = 'QuitWithFailure'
$jsn.OnFailAction = 'QuitWithFailure'
$jsn.Create()

Наконец, OnFailAction исходного завершающего шага устанавливается в значение 'GoToStep', а OnFailStep получает значение на единицу больше, чем последний шаг. Измените шаг и измените задание.

$jst.OnFailAction = 'GoToStep'
$jst.OnFailStep = $jsc + 1
$jst.Alter()
$job.Alter()
}

После того, как сценарий совершит циклический обход заданий на сервере, каждое задание будет иметь шаг уведомления о сбое, на котором отправляется электронное сообщение, оповещающее оператора об отказе.