Как точно определить, выполняется ли задание SQL Server, и справиться с уже запущенным заданием? - PullRequest
9 голосов
/ 02 мая 2011

В настоящее время я использую подобный код, чтобы определить, выполняется ли задание сервера 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: Текущий поток управления выглядит так:

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

Ответы [ 3 ]

4 голосов
/ 03 августа 2011

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

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

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

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

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

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

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

    SET CONTEXT_INFO 0x0
    
  4. Когда вы смотрите на вызов своей работы, сделайте это:

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

Когда ваш процесс оболочки завершается или соединение закрывается, ваш context_info исчезает.

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

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

2 голосов
/ 27 сентября 2014

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

-- 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 )
0 голосов
/ 10 июля 2013

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

...