Неопределенные расписания заданий в состоянии простоя процессора типа onidle не будут использоваться

Обновлено: 26.02.2024

API совместного планирования фоновых задач (также называемый API фоновых задач или API requestIdleCallback()) позволяет ставить задачи в очередь для автоматического выполнения агентом пользователя, когда он определяет, что есть свободное время для выполнения. так.

Примечание. Этот API недоступен в Web Workers.

Концепции и использование

Основной поток веб-браузера сосредоточен вокруг цикла обработки событий. Этот код рисует все ожидающие обновления отображаемого в данный момент документа, запускает любой код JavaScript, необходимый для запуска страницы, принимает события от устройств ввода и отправляет эти события элементам, которые должны их получать. Кроме того, цикл обработки событий обрабатывает взаимодействие с операционной системой, обновления собственного пользовательского интерфейса браузера и т. д. Это чрезвычайно загруженный кусок кода, и ваш основной код JavaScript может выполняться прямо внутри этого потока вместе со всем этим. Конечно, большая часть, если не весь код, способный вносить изменения в DOM, выполняется в основном потоке, поскольку обычно изменения пользовательского интерфейса доступны только в основном потоке.

Поскольку обработка событий и обновление экрана — это два наиболее очевидных способа, с помощью которых пользователи замечают проблемы с производительностью, важно, чтобы ваш код был добросовестным гражданином Интернета и помогал предотвращать зависания в выполнении цикла обработки событий. В прошлом не было другого способа сделать это надежно, кроме как писать максимально эффективный код и перекладывать как можно больше работы на рабочих. Window.requestIdleCallback() позволяет активно участвовать в обеспечении бесперебойной работы цикла событий браузера, позволяя браузеру сообщать вашему коду, сколько времени он может безопасно использовать, не вызывая задержки системы. Если вы останетесь в пределах заданного лимита, вы сможете значительно улучшить взаимодействие с пользователем.

Получение максимальной отдачи от бездействующих обратных вызовов

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

  • Используйте бездействующие обратные вызовы для задач, не имеющих высокого приоритета. Поскольку вы не знаете, сколько обратных вызовов было установлено, и вы не знаете, насколько занята система пользователя, вы не знаете, как часто будет выполняться ваш обратный вызов (если только вы не укажете тайм-аут). Нет никакой гарантии, что каждый проход через цикл обработки событий (или даже каждый цикл обновления экрана) будет включать любые выполняемые бездействующие обратные вызовы; если цикл событий использует все доступное время, вам не повезло (опять же, если вы не использовали тайм-аут).
  • Обратные вызовы бездействия должны делать все возможное, чтобы не превышать отведенное время. Хотя браузер, ваш код и Интернет в целом будут продолжать нормально работать, если вы превысите указанный лимит времени (даже если вы превысите его намного), ограничение по времени предназначено для обеспечения того, чтобы вы оставляете системе достаточно времени, чтобы завершить текущий проход через цикл событий и перейти к следующему, не вызывая заикания другого кода или задержки эффектов анимации. В настоящее время timeRemaining() имеет верхний предел в 50 миллисекунд, но на самом деле у вас часто будет меньше времени, чем это, поскольку цикл обработки событий может уже потреблять это время на сложных сайтах, с расширениями браузера, требующими процессорного времени, и т. д. .
  • Избегайте внесения изменений в DOM во время обратного вызова бездействия. К моменту запуска вашего обратного вызова текущий кадр уже закончил отрисовку, и все обновления макета и вычисления были завершены. Если вы вносите изменения, влияющие на макет, вы можете вызвать ситуацию, в которой браузер должен остановиться и выполнить перерасчеты, которые в противном случае были бы ненужными. Если ваш обратный вызов должен изменить DOM, он должен использовать Window.requestAnimationFrame() для планирования этого.
  • Избегайте задач, время выполнения которых невозможно предсказать. Обратный вызов бездействия должен избегать выполнения чего-либо, что может занять непредсказуемое количество времени. Например, следует избегать всего, что может повлиять на макет. Вам также следует избегать разрешения или отклонения промисов, так как это вызовет обработчик для разрешения или отклонения этого промиса, как только ваш обратный вызов вернется.
  • Используйте тайм-ауты, когда это необходимо, но только тогда, когда это необходимо. Использование тайм-аутов может гарантировать своевременное выполнение вашего кода, но также может позволить вам вызвать задержку или заикание анимации, предписывая браузеру вызывать вас, когда у вас недостаточно времени для выполнения, не нарушая производительность.

Возврат к setTimeout

Поскольку API фоновых задач является довольно новым, ваш код может нуждаться в возможности работать в браузерах, которые еще не поддерживают его. Вы можете сделать это с помощью простой прокладки, которая использует setTimeout() в качестве запасного варианта.Это не полифилл, так как он функционально не идентичен; setTimeout() не позволяет вам использовать периоды простоя, а вместо этого запускает ваш код, когда это возможно, предоставляя нам возможность сделать все возможное, чтобы не вызывать задержки производительности у пользователя.

Если значение window.requestIdleCallback не определено, мы создаем его здесь. Функция начинается с записи времени вызова нашей реализации. Мы будем использовать это для вычисления значения, возвращаемого нашей прокладкой для timeRemaining() .

Затем мы вызываем setTimeout() , передавая ей функцию, которая запускает обратный вызов, переданный в нашу реализацию requestIdleCallback() . Обратному вызову передается объект, который соответствует IdleDeadline , с didTimeout, установленным в false, и методом timeRemaining(), который реализован, чтобы дать обратному вызову 50 миллисекунд времени для начала. Каждый раз, когда вызывается функция timeRemaining(), она вычитает прошедшее время из исходных 50 миллисекунд, чтобы определить количество оставшегося времени.

В результате, хотя наша оболочка не ограничивает себя количеством времени простоя, оставшегося в текущем проходе цикла событий, как истинный requestIdleCallback() , она, по крайней мере, ограничивает обратный вызов не более чем 50 миллисекундами выполнения. время за проход.

Реализация нашей оболочки для cancelIdleCallback() намного проще:

Если функция cancelIdleCallback() не определена, создается функция, которая передает указанный идентификатор обратного вызова в функцию clearTimeout() .

Теперь ваш код будет работать даже в браузерах, не поддерживающих API фоновых задач, хотя и не так эффективно.

Интерфейсы

API фоновых задач добавляет только один новый интерфейс:

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

Оконный интерфейс также дополнен этим API, чтобы предложить новые методы requestIdleCallback() и cancelIdleCallback().

Пример

В этом примере мы рассмотрим, как можно использовать requestIdleCallback() для выполнения трудоемких задач с низким приоритетом в то время, когда в противном случае браузер бездействовал бы. Кроме того, в этом примере показано, как планировать обновления содержимого документа с помощью requestAnimationFrame() .

Ниже вы найдете только HTML и JavaScript для этого примера. CSS не показан, так как он не особенно важен для понимания этой функциональности.

HTML-контент

Чтобы понять, чего мы пытаемся достичь, давайте взглянем на HTML. Это устанавливает поле ( id = "container" ), которое используется для представления хода операции (потому что вы никогда не знаете, сколько времени займет декодирование "выбросов тахионного квантового волокна", в конце концов), а также второе основное поле ( id = "logBox" ), который используется для отображения текстового вывода.

В окне прогресса используется

элемент для отображения хода выполнения, а также метка с разделами, которые изменены для представления числовой информации о ходе выполнения. Кроме того, есть кнопка «Пуск» (творчески присвоенный идентификатор «startButton»), которую пользователь будет использовать для запуска обработки данных.

Контент JavaScript

Теперь, когда структура документа определена, создайте код JavaScript, который будет выполнять эту работу. Цель: иметь возможность добавлять запросы на вызов функций в очередь с обратным вызовом бездействия, который запускает эти функции всякий раз, когда система бездействует в течение достаточно долгого времени, чтобы добиться прогресса.

Объявления переменных

Эти переменные используются для управления списком задач, ожидающих выполнения, а также информацией о состоянии очереди задач и ее выполнении:

  • taskList – это массив объектов, каждый из которых представляет одну задачу, ожидающую выполнения.
  • totalTaskCount — счетчик количества задач, добавленных в очередь; он будет только подниматься, а не опускаться. Мы используем это, чтобы сделать математику, чтобы представить прогресс в процентах от общей работы, которую нужно сделать.
  • currentTaskNumber используется для отслеживания количества уже обработанных задач.
  • taskHandle — это ссылка на задачу, которая обрабатывается в данный момент.
  • totalTaskCountElem используется для вставки общего количества задач, созданных в поле статуса в поле прогресса.
  • currentTaskNumberElem — это элемент, используемый для отображения количества задач, обработанных на данный момент.
  • progressBarElem — это

Наконец, мы настроили пару переменных для других элементов:

  • logFragment будет использоваться для хранения DocumentFragment, сгенерированного нашими функциями ведения журнала, для создания содержимого, которое будет добавлено в журнал при отображении следующего кадра анимации.
  • statusRefreshScheduled используется для отслеживания того, запланировали ли мы уже обновление окна отображения состояния для предстоящего кадра, чтобы мы делали это только один раз за кадр

Управление очередью задач

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

Постановка задач в очередь

Во-первых, нам нужна функция, которая ставит задачи в очередь для будущего выполнения. Эта функция enqueueTask() выглядит так:

enqueueTask() принимает на вход два параметра:

  • taskHandler — это функция, которая будет вызываться для обработки задачи.
  • taskData – это объект, который передается обработчику задачи в качестве входного параметра, чтобы позволить задаче получать пользовательские данные.

Чтобы поставить задачу в очередь, мы помещаем объект в массив taskList; объект содержит значения taskHandler и taskData под именами handler и data соответственно, а затем увеличивает totalTaskCount , который отражает общее количество задач, когда-либо поставленных в очередь (мы не уменьшаем его, когда задачи удаляются из очереди).< /p>

Затем мы проверяем, не создали ли уже обратный вызов бездействия; если taskHandle равен 0, мы знаем, что обратного вызова бездействия еще нет, поэтому мы вызываем requestIdleCallback(), чтобы создать его. Он настроен на вызов функции runTaskQueue() , которую мы вскоре рассмотрим, и с тайм-аутом в 1 секунду, так что он будет запускаться по крайней мере один раз в секунду, даже если на самом деле нет доступного времени простоя.

Выполнение задач

Наш обработчик обратного вызова бездействия, runTaskQueue() , вызывается, когда браузер определяет, что имеется достаточно времени простоя, чтобы позволить нам выполнить какую-либо работу, или истекает время ожидания в одну секунду. Задача этой функции — запускать поставленные в очередь задачи.

Ядро runTaskQueue() представляет собой цикл, который продолжается до тех пор, пока остается время (определяемое проверкой срока. и пока в списке задач есть задачи.

Для каждой задачи в очереди, которую у нас есть время выполнить, мы делаем следующее:

  1. Мы удаляем объект задачи из очереди.
  2. Мы увеличиваем значение currentTaskNumber, чтобы отслеживать, сколько задач мы выполнили.
  3. Мы вызываем обработчик задачи, task.handler , передавая в него объект данных задачи ( task.data ).
  4. Мы вызываем функцию scheduleStatusRefresh() , чтобы управлять планированием обновления экрана, чтобы отражать изменения в нашем прогрессе.

По истечении времени, если в списке еще остались задачи, мы снова вызываем requestIdleCallback(), чтобы продолжить обработку задач в следующий раз, когда появится доступное время простоя. Если очередь пуста, мы устанавливаем для taskHandle значение 0, чтобы указать, что у нас нет запланированного обратного вызова. Таким образом, мы будем знать, что нужно запросить обратный вызов при следующем вызове enqueueTask().

Обновление отображения статуса

Одна вещь, которую мы хотим сделать, — это обновить наш документ, указав в нем выходные данные журнала и информацию о ходе выполнения. Однако вы не можете безопасно изменить DOM из обратного вызова бездействия. Вместо этого мы будем использовать requestAnimationFrame(), чтобы попросить браузер вызвать нас, когда можно будет безопасно обновить отображение.

Планирование обновлений дисплея

Изменения DOM планируются вызовом функции scheduleStatusRefresh().

Это простая функция. Он проверяет, запланировали ли мы уже обновление дисплея, проверяя значение statusRefreshScheduled. Если оно равно false , мы вызываем requestAnimationFrame(), чтобы запланировать обновление, предоставляя функцию updateDisplay() для выполнения этой работы.

Обновление отображения

Функция updateDisplay() отвечает за отрисовку содержимого окна прогресса и журнала. Он вызывается браузером, когда DOM находится в безопасном состоянии для применения изменений в процессе рендеринга следующего кадра.

Во-первых, для scrolledToEnd устанавливается значение true, если текст в журнале прокручивается вниз; в противном случае устанавливается значение false . Мы воспользуемся этим, чтобы определить, следует ли обновить положение прокрутки, чтобы журнал оставался в конце, когда мы закончим добавлять в него контент.

Далее мы обновляем информацию о ходе выполнения и статусе, если какие-либо задачи поставлены в очередь.

  1. Если текущее максимальное значение индикатора выполнения отличается от текущего общего количества поставленных в очередь задач ( totalTaskCount ), мы обновляем содержимое отображаемого общего количества задач ( totalTaskCountElem ) и максимальное значение индикатора выполнения, чтобы он правильно масштабировался.
  2. То же самое мы делаем с количеством уже обработанных задач; если progressBarElem.value отличается от номера обрабатываемой в данный момент задачи ( currentTaskNumber ), то мы обновляем отображаемое значение текущей обрабатываемой задачи и текущее значение индикатора выполнения.

Затем, если есть текст, ожидающий добавления в журнал (то есть, если logFragment не равен null ), мы добавляем его к элементу журнала с помощью Element.appendChild() и устанавливаем для logFragment значение null, чтобы не добавьте еще раз.

Если журнал был прокручен до конца, когда мы начали, мы удостоверимся, что это все еще так. Затем мы устанавливаем для параметра statusRefreshScheduled значение false, чтобы указать, что мы обработали обновление и безопасно запросить новое.

Добавление текста в журнал

Функция log() добавляет указанный текст в журнал. Поскольку в момент вызова log() мы не знаем, безопасно или нет сразу прикасаться к DOM, мы будем кэшировать текст журнала до тех пор, пока его можно будет безопасно обновить. Выше, в коде для updateDisplay() , вы можете найти код, который фактически добавляет записанный текст в элемент журнала при обновлении кадра анимации.

Сначала мы создаем объект DocumentFragment с именем logFragment, если он еще не существует. Этот элемент представляет собой псевдо-DOM, в который мы можем вставлять элементы, не изменяя непосредственно сам основной DOM.

Затем мы создаем новый

и установите его содержимое в соответствии с введенным текстом. Затем мы добавляем новый элемент в конец псевдо-DOM в logFragment. logFragment будет накапливать записи журнала до следующего вызова updateDisplay() из-за DOM для изменений.

Выполнение задач

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

Обработчик задач

Функция, которую мы будем использовать в качестве обработчика задачи, то есть функция, которая будет использоваться в качестве значения свойства обработчика объекта задачи, — это logTaskHandler (). Это простая функция, которая выводит кучу информации в лог для каждой задачи. В своем собственном приложении вы замените этот код любой задачей, которую хотите выполнить во время простоя. Просто помните, что все, что вы хотите сделать, чтобы изменить DOM, должно быть обработано через requestAnimationFrame() .

Основная программа

Все запускается, когда пользователь нажимает кнопку "Пуск", что вызывает вызов функции decodeTechnoStuff().

decodeTechnoStuff() начинает с обнуления значений totalTaskCount (количество задач, добавленных в очередь на данный момент) и currentTaskNumber (задача, выполняемая в данный момент), а затем вызывает updateDisplay() для сброса дисплея в состояние "ничего не произошло". пока" состояние.

В этом примере будет создано случайное количество задач (от 100 до 200). Для этого мы используем функцию getRandomIntInclusive(), приведенную в качестве примера в документации для Math.random(), чтобы получить количество создаваемых задач.

Затем мы запускаем цикл для создания актуальных задач. Для каждой задачи мы создаем объект taskData , который включает два свойства:

  • count – это количество строк, которые необходимо вывести в журнал из задачи.
  • text – это текст, который будет выводиться в журнал столько раз, сколько указано в параметре count .

Затем каждая задача ставится в очередь путем вызова enqueueTask() , передачи logTaskHandler() в качестве функции-обработчика и объекта taskData в качестве объекта для передачи в функцию при ее вызове.

Результат

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

Если задание должно выполняться ежечасно с 3:00 до 7:00, один раз в 00:00 и каждый час с 18:00 до 21:00 каждый день, как вы запланируете задание на сервере SQL? Если ваш ответ на вопрос состоит в том, чтобы определить три отдельных задания, после прочтения этой статьи вы получите лучший способ.

SQL server имеет очень гибкую систему планирования. Эта статья будет посвящена следующим темам:

  • Прикрепление нескольких расписаний к заданию
  • Расписания для частого выполнения (вкладка "Дополнительно" интервала расписания:


Согласно BOL:

· Средняя загрузка ЦП падает ниже:

Укажите состояние бездействия ЦП в процентах. Бездействие — это когда среднее использование ЦП остается ниже выбранного процента в течение указанного количества секунд.

· И остается ниже этого уровня в течение

Укажите состояние бездействия ЦП в секундах. Бездействие — это когда среднее использование ЦП остается ниже выбранного процента в течение указанного количества секунд.

Если условие бездействия ЦП не определено, SQL-сервер не выдает никаких сообщений об ошибках, когда вы определяете задания для выполнения на бездействии ЦП. Однако сервер агента SQL выдает сообщение в журнале ошибок при запуске, если условие простоя не определено:

2006-02-07 08:24:00 - + [396] Состояние простоя ЦП не определено - задание OnIdle

расписания не действуют

Чтобы использовать это расписание, в свойствах задания агента SQL -> вкладка расписания выберите «Новое расписание…» или «Редактировать…» и

выберите второй вариант в «Тип расписания» следующим образом:


Чтобы определить расписание, вызвав хранимую процедуру msdb.dbo.sp_add_jobschedule, нам нужно передать 128 для @freq_type.

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

Запуск задания при запуске сервера агента SQL

Задание с этим типом расписания запускается после запуска сервера агента SQL. Это подходит для очистки или настройки рабочей среды для других заданий, например. создать или очистить определенную папку и т. д. Чтобы использовать это расписание, в свойствах задания агента SQL -> вкладка расписания выберите «Новое расписание…» или «Редактировать…» и выберите первый вариант в «Тип расписания» как


Чтобы определить расписание, вызвав хранимую процедуру msdb.dbo.sp_add_jobschedule, нам нужно передать 64 для @freq_type.

Заключение

SQL server имеет очень гибкую систему планирования. Специальные нерегулярные расписания могут быть определены для задания путем комбинирования различных типов расписаний, таких как повторяющееся, однократное или простоя ЦП и т. д.

В SQL Server 2005 задание и расписание разделены. Таким образом, расписания могут совместно использоваться несколькими заданиями.

Эд Поллак

Агент SQL Server позволяет нам создавать задания и назначать им любое количество расписаний. Это обеспечивает большую гибкость при принятии решения о том, когда следует запускать задания. Со временем, по мере увеличения количества заданий и расписаний на данном SQL Server, становится сложно полностью понять, когда и как часто задания выполняются в течение заданного промежутка времени.

Общая потребность заключается в возможности быстрого создания списка заданий, которые будут выполняться в течение заданного периода времени. Информация о том, когда (и как часто) выполняются задания, может помочь нам лучше планировать мероприятия по обслуживанию и гарантировать, что мы не пропустим ничего важного, когда агент SQL Server не работает.

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

Предпосылки

В нашем коде будет использоваться таблица календаря, чтобы мы могли быстро анализировать даты и назначать такие показатели, как день недели и неделя месяца. Здесь мы будем использовать таблицу календаря, представленную в предыдущей статье SQL Shack: Создание таблицы календаря

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

Планирование и примечания

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

Все даты и время, хранящиеся в MSDB, хранятся в часовом поясе локального сервера. Это означает, что обмен данными между серверами или преобразование из UTC могут быть проблематичными. Чтобы упростить эту задачу, мы построим наш процесс для приема и возврата данных как в формате UTC, так и в местных часовых поясах. Это облегчит задачу преобразования часовых поясов в случае, если сервер не использует время UTC.

Заданиям могут быть назначены разные графики. Мы хотим рассмотреть их все следующим образом:

  • Ежедневные задания, которые выполняются каждый день или несколько дней в неделю.
  • Еженедельные задания, которые выполняются каждую неделю в определенные дни.
  • Ежемесячные задания, выполняемые в определенный набор дней в течение месяца.
  • Одноразовые задания, предназначенные для выполнения один раз и никогда больше.
  • Задания, которые выполняются несколько раз по любому из указанных выше расписаний.
  • Задания, которые запускаются при запуске агента или при простое сервера (для отчетов)

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

Поскольку у задания может быть несколько расписаний, мы должны рассматривать каждую комбинацию задания и расписания как отдельный объект. Это гарантирует, что мы будем фиксировать запуски заданий, запускаемые всеми расписаниями, используемыми в задании.

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

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

Объекты MSDB

Задания агента SQL Server, расписания и история выполнения хранятся в системной базе данных MSDB. Дизайн этих таблиц не сильно изменился за эти годы, и в результате их содержимое немного сложно читать. Ниже приведен список схем в MSDB, которые мы будем использовать для нашей работы:

Sysjobs: эта таблица содержит строку для каждого задания, определенного в агенте SQL Server. Включены столбцы, которые определяют имя задания, описание, если оно включено, его категорию, начальный этап, дату создания/изменения и множество других параметров, влияющих на общее функционирование задания.

  • Freq_type: число из следующего списка, указывающее, как часто выполняется задание: 1 = Однократно, 4 = Ежедневно, 8 = Еженедельно, 16 = Ежемесячно (в определенные дни), 32 = Ежемесячно относительно (в заданное время месяца, например, 3-й вторник или в прошлую пятницу) , 64 = При запуске агента SQL Server и 128 = Когда сервер простаивает
  • Freq_interval: если расписание выполняется каждые N дней/недель или в определенный день/неделю месяца, то freq_interval будет указывать эту частоту выполнения, в противном случае он указывает, в какие дни недели происходит работа. Для дней недели эти дни задаются как двоичная сумма: 1 = воскресенье, 2 = понедельник, 4 = вторник, 8 = среда, 16 = четверг, 32 = пятница и 64 = суббота. Например, 127 будет означать, что задание выполняется каждый день, а 13 – задание, которое выполняется в воскресенье, вторник и среду.
  • Freq_subday_type: если 1, то задание выполняется только в определенное время. Если задание выполняется каждые N секунд, минут или часов, то для него будет установлено значение 2 для секунд, 4 для минут или 8 для часов. 0 указывает, что это не используется, например, для задания, которое запускается при запуске агента SQL Server
  • Freq_subday_interval: если freq_subday_type указывает на задание, которое выполняется каждые N секунд/минут/часов, в этом столбце будет число, указывающее, сколько секунд/минут/часов пройдет между запусками задания< /li>
  • Freq_relative_interval: если задание выполняется в N-й день месяца, это указывает, что такое N. 0 = не используется (для других типов расписаний), 1 = 1-е, 2 = 2-е, 4 = 3-е, 8 = 4-е и 16 = последнее
  • Freq_recurrence_factor: если задание выполняется каждые N недель или месяцев, в этом столбце указано значение N. 0 означает, что он не используется для данного типа расписания. Используется только для ежедневных, еженедельных или ежемесячных расписаний.
  • Active_start_date и Active_end_date: сообщают нам, когда задание активно и будет запущено. Если текущая дата находится за пределами этого диапазона, задание не будет выполняться
  • Active_start_time и Active_end_time: определяют границы времени выполнения задания в течение дня. Если текущее время не находится в этом диапазоне, задание не будет выполнено

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

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

Syscategories: эта таблица содержит список всех категорий, определенных в агенте SQL Server. Категории должностей можно использовать для классификации должностей, чтобы упростить их группировку и понимание. Мы включаем это в информационных целях, но категории можно использовать для настройки мониторинга и оповещений в зависимости от цели или важности задания.

Agent_datetime (год ГГГГММДД, время ЧЧММСС): эта функция плохо документирована, но преобразует целочисленные даты и время, хранящиеся во многих таблицах MSDB (таких как sysschedules), в DATETIME. Это очень удобно и избавит нас от необходимости писать беспорядочную кучу TSQL для выполнения этого преобразования. В информационных целях вот TSQL, стоящий за этой функцией:

Читайте также: