Планировщик задач DocScheduler (CRON_TABLE)
Планировщик DocScheduler предназначен для периодического запуска задач (CSP‑сервисов или DB‑функций) по расписанию, задаваемому с помощью SQL‑выражений. Управление задачами осуществляется через документы типа CRON_TABLE.
Планировщик автоматически отслеживает выполнение запущенных процессов, фиксирует ошибки, рассчитывает следующее время запуска и при необходимости переводит задачу в неактивное состояние (по превышению лимита ошибок или невалидному расписанию).
Документ CRON_TABLE: поля и их назначение
Для создания задачи необходимо добавить документ с dockind = "CRON_TABLE" и статусом "CRON_TABLE_ACTIVE".
Поддерживаются следующие свойства:
| Поле | Тип | Описание |
|---|---|---|
NUM |
число/строка | Идентификатор (номер) задачи. |
DESCR |
строка | Описание задачи (назначение). |
SYS_PROCESS_ID |
число | ID запущенного системного процесса (заполняется автоматически). |
DB_FUNCTION |
строка | Имя DB‑функции для вызова (если не используется CSP). |
CSP_SERVICE |
строка | Имя CSP‑сервиса для вызова. |
CSP_SERVICE_PARAMS |
строка (JSON) | Параметры вызова CSP‑сервиса в формате JSON. |
INTERVAL |
строка | SQL‑выражение, вычисляющее следующую дату/время запуска (см. ниже). |
INTERVAL_ERROR |
строка | SQL‑выражение для следующего запуска после ошибки (если не задано, используется INTERVAL). |
MAX_COUNT_ERROR |
число | Максимальное количество последовательных ошибок, после которого задача переводится в статус CRON_TABLE_ERROR. |
COUNT_ERROR |
число | Текущий счётчик последовательных ошибок (заполняется автоматически). |
FIRST_RUN |
datetime | Первый запланированный запуск (опционально, используется для проверки). |
LAST_RUN |
datetime | Время последнего запуска (заполняется автоматически). |
NEXT_RUN |
datetime | Следующее время запуска (рассчитывается автоматически). |
DAILY_START_TIME |
datetime | Время фактического начала выполнения задачи (заполняется автоматически). |
DAILY_END_TIME |
datetime | Время окончания выполнения задачи (заполняется автоматически). |
ERROR_TEXT |
строка | Текст последней ошибки (заполняется автоматически). |
PERIODICAL_RUN |
не используется | (зарезервировано) |
DEL_ON_FINISH |
не используется | (зарезервировано) |
Важно: Для запуска задачи необходимо указать либо
CSP_SERVICE(с возможнымиCSP_SERVICE_PARAMS), либоDB_FUNCTION.
Принцип работы планировщика
1. Загрузка задач
При старте и далее каждые 10 минут или при изменениях в CRON_TABLE (таймер reloadTimer) планировщик перечитывает все активные документы CRON_TABLE_ACTIVE.
Также перезагрузка происходит при любом изменении статуса системного процесса (через триггер trgProcessChanged) — например, после завершения задачи.
2. Цикл проверки расписания
Каждые 30 секунд (таймер checkTimer) планировщик:
- Собирает задачи, у которых
NEXT_RUN <= текущего временииSYS_PROCESS_IDотсутствует (т.е. процесс не запущен). - Запускает полную перезагрузку задач и их обработку, при наличии собранных задач
3. Обработка задачи (_processTask)
Для каждой активной задачи выполняется логика:
Если NEXT_RUN в будущем → пропустить
Иначе если SYS_PROCESS_ID отсутствует → запустить задачу (_runTask)
Иначе если процесс с таким ID не найден в sysprocs → запустить задачу заново
Иначе если процесс завершён с ошибкой → вызвать _finishTask с текстом ошибки
Иначе если процесс завершён успешно → вызвать _finishTask без ошибки
Иначе процесс ещё выполняется → ничего не делать
4. Запуск задачи (_runTask)
- Создаётся новый системный процесс:
- тип
csp– для вызова CSP‑сервиса (параметры берутся изCSP_SERVICE_PARAMS); - тип
db– для вызова DB‑функции.
- тип
- В документе CRON_TABLE проставляется
SYS_PROCESS_IDи текущее время вDAILY_START_TIME. - После этого планировщик перезагружает списки задач и процессов.
Если на этапе запуска возникает исключение, вызывается _finishTask с текстом ошибки.
5. Завершение задачи / расчёт следующего запуска (_finishTask)
Шаги:
-
Определение интервала
- Если есть ошибка → используется
INTERVAL_ERROR(илиINTERVAL, еслиINTERVAL_ERRORне задан). - Если ошибки нет → используется
INTERVAL.
- Если есть ошибка → используется
-
Обновление счётчика ошибок
- При ошибке:
COUNT_ERRORувеличивается на 1. - При успехе:
COUNT_ERRORсбрасывается в 0.
- При ошибке:
-
Проверка лимита ошибок
- Если
COUNT_ERROR > MAX_COUNT_ERROR→ задача переводится в статусCRON_TABLE_ERRORи больше не запускается.
- Если
-
Расчёт следующего времени запуска
- Выполняется SQL‑запрос:
SELECT (<INTERVAL_выражение>) as RESULT. - Результат преобразуется в
dayjs‑объект. - Если выражение пустое, результат невалиден или запрос не удался → задача переводится в статус
CRON_TABLE_PASSIVE(отключена). - Иначе
NEXT_RUNустанавливается на вычисленную дату/время.
- Выполняется SQL‑запрос:
-
Обновление документа
- Сбрасывается
SYS_PROCESS_ID, проставляетсяDAILY_END_TIME,ERROR_TEXT, новыйNEXT_RUNиCOUNT_ERROR. - При необходимости изменяется статус документа (на
CRON_TABLE_ERRORилиCRON_TABLE_PASSIVE). - Выполняется перезагрузка списков задач и процессов.
- Сбрасывается
Настройка расписания (INTERVAL и INTERVAL_ERROR)
Планировщик не использует классические cron‑выражения. Вместо этого для вычисления следующей даты запуска применяются произвольные SQL‑выражения, возвращающие timestamp.
Формат
Выражение должно быть валидным SQL‑выражением для СУБД, на которой работает MorphCluster. Рекомендуется использовать NOW() как точку отсчёта.
Примеры
| Цель | SQL‑выражение для INTERVAL |
|---|---|
| Каждые 5 минут | NOW() + INTERVAL '5 minutes' |
| Каждый час | NOW() + INTERVAL '1 hour' |
| Ежедневно в 03:00 | DATE_TRUNC('day', NOW()) + INTERVAL '1 day' + INTERVAL '3 hours' |
| Каждый понедельник в 09:00 | NEXT_DAY(NOW(), 'MONDAY') + INTERVAL '9 hours' (зависит от диалекта SQL) |
| Через 1 день после успешного выполнения | NOW() + INTERVAL '1 day' |
Особенность при пустом INTERVAL
Если INTERVAL (и INTERVAL_ERROR) не заданы, то:
- После успешного выполнения задачи
NEXT_RUNостанетсяNULL. - При следующем цикле проверки планировщик будет считать, что
NEXT_RUNуже наступил (условиеtask.NEXT_RUN && task.NEXT_RUN.isAfter(...)не сработает, т.к.NEXT_RUN—null). - В результате задача будет запускаться повторно сразу после предыдущего завершения (зацикливание).
Рекомендация: всегда задавайте явное INTERVAL или переводите задачу в неактивный статус вручную после разового выполнения.
Обработка ошибок и отказоустойчивость
-
Счётчик ошибок (
COUNT_ERROR) увеличивается при любом сбое:- Ошибка запуска задачи (исключение в
_runTask). - Завершение системного процесса со статусом
failed.
- Ошибка запуска задачи (исключение в
-
Раздельный интервал после ошибки позволяет задать более частое повторение (например,
NOW() + INTERVAL '5 minutes') или более длительную паузу. -
Лимит ошибок (
MAX_COUNT_ERROR): по достижении лимита задача автоматически деактивируется (статусCRON_TABLE_ERROR). Это предотвращает бесконечные попытки заведомо ошибочной задачи. -
Невалидное расписание (ошибка вычисления
NEXT_RUNили пустойINTERVAL) переводит задачу в статусCRON_TABLE_PASSIVE— она исключается из обработки до ручного вмешательства.
Жизненный цикл задачи (на примере)
-
Создание
Добавляется документCRON_TABLEсо статусомACTIVE, заполняются поляCSP_SERVICE/DB_FUNCTION,INTERVAL,MAX_COUNT_ERROR(опционально). -
Первый запуск
- Если
NEXT_RUNне задан илиNEXT_RUN <= текущего времени→ планировщик запускает задачу. -
SYS_PROCESS_IDполучает ID нового системного процесса. -
DAILY_START_TIMEфиксирует момент старта.
- Если
-
Выполнение
Планировщик не вмешивается в ход работы процесса. Процесс выполняется асинхронно. -
Завершение процесса
- Системный процесс переходит в статус
completedилиfailed. - Триггер
trgProcessChangedнемедленно вызывает перезагрузку планировщика. - Планировщик обрабатывает завершённую задачу через
_finishTask:- Рассчитывается
NEXT_RUN(с учётом ошибки, если была). - Обновляются
COUNT_ERROR,DAILY_END_TIME,ERROR_TEXT. - Сбрасывается
SYS_PROCESS_ID. - При необходимости меняется статус документа.
- Рассчитывается
- Системный процесс переходит в статус
-
Повторный запуск
Когда текущее время достигнет новогоNEXT_RUN, планировщик снова запустит задачу. -
Отключение задачи
- Автоматически: при превышении
MAX_COUNT_ERRORили невалидномINTERVAL. - Вручную: изменить статус документа на любой, кроме
CRON_TABLE_ACTIVE.
- Автоматически: при превышении
Особенности и ограничения
1. Механизм блокировки повторной перезагрузки
- Используется флаг
reloadingи отложенный вызовneedReloadдля предотвращения одновременной перезагрузки из разных таймеров/триггеров.
2. Сессия выполнения
- Задачи запускаются от имени пользователя
userId = 5056с правами администратора (isAdmin: true). - Это зашито в коде и не настраивается через CRON_TABLE.
3. Поведение при NEXT_RUN = NULL
Как уже отмечено, это приводит к немедленному повторному запуску после завершения. Если вам нужно однократное выполнение, после успеха следует вручную перевести задачу в статус CRON_TABLE_PASSIVE или CRON_TABLE_ERROR (например, через отдельный процесс).
4. Типы вызываемых функций
-
CSP‑сервис – должен быть зарегистрирован в системе. Параметры передаются через
CSP_SERVICE_PARAMSв виде JSON-строки. - DB‑функция – хранимая функция в базе данных. Вызов происходит без параметров (но можно передать через глобальные переменные сессии или отдельный механизм).
Рекомендации по настройке
-
Всегда задавайте
INTERVALдаже для периодических задач. Для разовых задач используйте ручное отключение или запланируйте удаление документа после выполнения. -
Указывайте
MAX_COUNT_ERROR– разумное значение (например, 3–5) для защиты от «зависших» ошибочных задач. -
Используйте
INTERVAL_ERROR, если после сбоя нужно повторить попытку быстрее, чем обычно. -
Проверяйте SQL‑выражения в консоли базы данных перед внесением в
INTERVAL. - Избегайте слишком частых запусков менее 30 секунд
Пример документа CRON_TABLE
{
"dockind": "CRON_TABLE",
"status": "CRON_TABLE_ACTIVE",
"props": {
"NUM": 101,
"DESCR": "Ежечасная архивация логов",
"DB_FUNCTION": "archive_logs",
"INTERVAL": "NOW() + INTERVAL '1 hour'",
"INTERVAL_ERROR": "NOW() + INTERVAL '5 minutes'",
"MAX_COUNT_ERROR": 3,
"FIRST_RUN": "2025-01-01T00:00:00"
}
}
Этот документ заставит планировщик вызывать DB‑функцию archive_logs каждый час. При возникновении ошибки следующая попытка будет через 5 минут. После трёх последовательных ошибок задача перейдёт в статус CRON_TABLE_ERROR.
Заключение
Планировщик DocScheduler предоставляет гибкий механизм запуска задач по расписанию на основе SQL‑выражений. Настройка через документы CRON_TABLE позволяет динамически добавлять, изменять и отключать задачи без перезапуска сервиса. Важно правильно заполнять поля INTERVAL и контролировать обработку ошибок через MAX_COUNT_ERROR и INTERVAL_ERROR.
No Comments