В настоящее время я использую подобный код, чтобы определить, выполняется ли задание сервера 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 должен обрабатывать!
Когда это происходит, выполняемое задание просто умирает, но не сразу, как я могу сказать, просто довольно близко. Я поместил регистрацию повсеместно, и нет никакой последовательности. Один раз это не удастся, это будет на месте а, в следующий раз на месте б. В некоторых случаях место A и место B имеют только
select @var = 'message'
между ними. Очень странно. По сути, задание выглядит как бесцеремонный дамп, и все, что осталось выполнить в задании, + не + выполнено вообще.
Однако, если я удаляю exec StartJob (или он вызывается ровно один раз, когда я ЗНАЮ, что целевое задание уже не может быть запущено), все работает отлично, и вся моя обработка в задании проходит.
Цель всего этого состоит в том, чтобы запустить задание в результате триггера (среди прочего), и, если задание уже запущено, на самом деле нет необходимости "запускать его заново".
Кто-нибудь когда-нибудь сталкивался с таким поведением при обработке заданий агента SQL?
EDIT:
Текущий поток управления выглядит так:
- Изменить на таблицу (обновить или вставить) ...
- срабатывает триггер, который вызывает ...
- сохраненный процесс, который вызывает ...
- sp_Start_Job which ...
- запускает определенную работу, которая ...
- вызывает другой сохраненный процесс (называемый CheckQueue), который ...
- выполняет некоторую обработку и ...
- проверяет несколько таблиц и в зависимости от их содержимого может ...
- вызовите sp_start_job на другой работе, чтобы запустить вторую одновременную работу
для обработки дополнительной работы (эта вторая работа также вызывает sproc CheckQueue
но эти два вызова работают с совершенно отдельными наборами данных)