Как точно определить, выполняется ли задание SQL Server, и справиться с уже запущенным заданием?

в настоящее время я использую такой код, чтобы определить, выполняется ли задание SQL server. (это 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 отказался запустить задание, потому что он уже есть отложенный запрос".

Ok. Тоже не проблема. Вполне возможно, что есть небольшое окно, где целевое задание может быть запущено до того, как этот код сможет запустить его, но после проверки, если он запущен. Тем не менее, я могу просто обернуть это в 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 agent поднимет ошибку, она поймана, и обработка просто продолжается, поскольку работа уже запущена, никакого вреда не будет.

но иногда я получаю сообщение в представлении истории заданий (имейте в виду приведенный выше код, чтобы определить, выполняется ли конкретное задание, и запустить его, если нет, на самом деле выполняется из другого задания), говоря, что задание не удалось, потому что "SQLAgent отказался запустить задание, потому что у него уже есть ожидающий запрос".

конечно, это точная ошибка, которую TRY CATCH должен обрабатывать!

при этом случается, что исполняющая работа просто умирает, но не сразу из того, что я могу сказать, просто довольно близко. Я разбросал журналы повсюду, и нет никакой последовательности. Один раз это не сработает, это будет на месте а, в следующий раз на месте Б. В некоторых случаях место A и место B не имеют ничего, кроме a

select @var = 'message'

между ними. Очень странный. В принципе, задание кажется бесцеремонно сброшенным, и все, что осталось выполнить в задании, вообще не выполняется.

однако, если я удалите "exec StartJob" (или вызовите его ровно один раз, когда я знаю, что целевое задание уже не может быть запущено), все работает отлично, и вся моя обработка в задании выполняется.

цель всего этого-запустить работу в результате триггера (среди прочего), и, если работа уже запущена, действительно нет необходимости "запускать ее снова".

кто-нибудь когда-либо сталкивался с подобным поведением с заданием агента SQL обращение?

изменить: Текущий поток управления выглядит так:

  1. изменить на таблицу (обновить или вставить)...
  2. срабатывает триггер, который вызывает...
  3. сохраненный proc, который вызывает...
  4. пакета sp_start_job, который...
  5. запускает определенную работу, которая...
  6. вызывает другой сохраненный proc (называемый CheckQueue), который...
  7. выполняет некоторую обработку и...
  8. проверяет несколько таблиц и в зависимости от на их содержание может...
  9. вызовите sp_start_job в другом задании, чтобы запустить второе одновременное задание для обработки дополнительной работы (это второе задание также вызывает checkqueue sproc но два вызова работают на совершенно разных наборах данных)

3 ответов


прежде всего, у вас была возможность посмотреть на Service broker? Судя по твоему описанию, это то, чего ты на самом деле хочешь.

разница была бы вместо запуска задания, вы помещаете свои данные в очередь SB, и SB будет вызывать вашу обработку асинхронно и полностью побочные проблемы с уже запущенными заданиями и т. д. Он автоматически порождает / прекращает дополнительные потоки и диктует спрос,он заботится о порядке и т. д.

вот хороший (и смутно связанный) учебник. http://www.sqlteam.com/article/centralized-asynchronous-auditing-with-service-broker

предположим, что вы не можете использовать SB по какой-либо причине (но серьезно, сделайте!).

как насчет использования context_info spid задания.

  1. ваша работа вызывает оболочку proc, которая выполняет каждый шаг отдельно.
  2. первый оператор внутри оболочки proc

    DECLARE @context_info VARBINARY(30)
    SET @context_info = CAST('MyJob1' AS VARBINARY)
    SET CONTEXT_INFO @context_info
    
  3. когда ваш proc заканчивается (или в вашем блоке catch)

    SET CONTEXT_INFO 0x0
    
  4. когда вы смотрите на вызов вашей работы, сделайте следующее:

    IF NOT EXISTS (SELECT * FROM master..sysprocesses WITH (NOLOCK) WHERE context_info=CAST('MyJob1' AS VARBINARY))
        EXEC StartJob
    

когда ваша оболочка proc завершается или соединение закрывается, ваш context_info уходит.

вы также можете использовать глобальную временную таблицу (т. е. ##JobStatus), они исчезнут, когда все spids, которые ссылаются на нее, отключатся или если это явно упал.

всего несколько мыслей.


У меня есть запрос, который дает мне запущенные задания, возможно, он может вам помочь. Это работает на меня, но если вы найдете в этом какой-либо недостаток, дайте мне знать, я постараюсь исправить. овации.

-- get the running jobs
--marcelo miorelli
-- 10-dec-2013


SELECT sj.name
      ,DATEDIFF(SECOND,aj.start_execution_date,GetDate()) AS Seconds
 FROM msdb..sysjobactivity aj
 JOIN msdb..sysjobs sj on sj.job_id = aj.job_id
WHERE aj.stop_execution_date IS NULL -- job hasn't stopped running
 AND aj.start_execution_date IS NOT NULL -- job is currently running
--AND sj.name = 'JobName'
and not exists( -- make sure this is the most recent run
    select 1
    from msdb..sysjobactivity new
    where new.job_id = aj.job_id
      and new.start_execution_date > aj.start_execution_date )

для работы с уже запущенной работой: 1. Ясли Для Открытых Задач 2. Проверьте, является ли процесс с ImageName " DTExec.exe " работает 3. Если процесс запущен и если это проблемное задание, выполните "завершить процесс".