В настоящее время я использую такой код, чтобы определить, выполняется ли задание SQL-сервера. (это SQL Server 2005, все SP)
return (select isnull(
(select top 1 CASE
WHEN current_execution_status = 4 THEN 0
ELSE 1
END
from openquery(devtestvm, 'EXEC msdb.dbo.sp_help_job')
where current_execution_status = 4 and
name = 'WQCheckQueueJob' + cast(@Index as varchar(10))
), 1)
)
Никаких проблем там нет, и вообще говоря, он работает просто отлично.
Но.... (всегда но)
Иногда я вызываю это, получаю результат «задание не выполняется», после чего я пытаюсь запустить задание через
exec msdb.dbo.sp_start_job @JobName
и SQL вернет, что «SQLAgent отказался запускать задание, потому что у него уже есть ожидающий запрос».
В порядке. Тоже не проблема. Вполне возможно, что есть небольшое окно, в котором целевое задание может быть запущено до того, как этот код сможет его запустить, но после проверки того, запущено ли оно. Однако я могу просто обернуть это в try catch и просто проигнорировать ошибку, верно?
begin try
if dbo.WQIsQueueJobActive(@index) = 0 begin
exec msdb.dbo.sp_start_job @JobName
break
end
end try begin catch
-- nothing here
end catch
вот проблема однако.
В 9 случаях из 10 это работает просто отлично. Агент SQL вызовет ошибку, она будет обнаружена, и обработка продолжится, так как задание уже запущено, без вреда для здоровья.
Но иногда я получаю сообщение в представлении «История заданий» (имейте в виду приведенный выше код, чтобы определить, выполняется ли конкретное задание, и запустить его, если оно на самом деле не выполняется из другого задания), в котором говорится, что задание не выполнено, потому что «SQLAgent отказался запускать задание, потому что оно уже имеет ожидающий запрос».
Конечно, это именно та ошибка, которую TRY CATCH должен обрабатывать!
Когда это происходит, выполняемая работа просто умирает, но не сразу, насколько я могу судить, просто довольно близко. Я поставил регистрацию повсюду, и нет согласованности. Один раз он потерпит неудачу, он будет в месте а, в следующий раз в месте б. В некоторых случаях место А и место Б не имеют ничего, кроме
select @var = 'message'
между ними. Очень странно. По сути, задание выглядит бесцеремонно сброшенным, и все, что осталось выполнить в задании, +не+ выполняется вообще.
Однако, если я удалю «exec StartJob» (или вызову его ровно один раз, когда я ЗНАЮ, что целевое задание уже не может быть запущено), все работает отлично, и вся моя обработка в задании выполняется.
Целью всего этого является запуск задания в результате срабатывания триггера (среди прочего), и, если задание уже запущено, нет необходимости «запускать его снова».
Кто-нибудь когда-либо сталкивался с подобным поведением при обработке заданий агента SQL?
РЕДАКТИРОВАТЬ: Текущий поток управления выглядит так:
- Перейти к таблице (обновить или вставить)...
- срабатывает триггер, который вызывает...
- хранимая процедура, которая вызывает...
- sp_Start_Job, который...
- запускает определенную работу, которая...
- вызывает другой хранимый процесс (называемый CheckQueue), который...
- выполняет некоторую обработку и...
- проверяет несколько таблиц и в зависимости от их содержимого может...
- вызвать sp_start_job для другого задания, чтобы запустить второе одновременное задание для обработки дополнительной работы (это второе задание также вызывает sproc CheckQueue, но два вызова работают с совершенно разными наборами данных)