Skip to content
  1. Компоненты
  2. MiniShop3
  3. Разработка
  4. Scheduler

Интеграция с Scheduler ​

MiniShop3 выполняет фоновые задачи через компонент Scheduler.

Требования ​

Scheduler 1.8.0 или выше. На более ранних версиях задачи работают, но повторяющиеся не перезапускаются автоматически.

Включение интеграции ​

  1. Установите компонент Scheduler и настройте для него cron — см. Установка и настройка запуска.
  2. Включите настройку ms3_use_scheduler: Система → Системные настройки → minishop3.

Настройка управляет только уведомлениями

ms3_use_scheduler читается в единственном месте — при решении, отправить уведомление сразу или поставить в очередь. На остальные задачи она не влияет:

  • уведомления уходят в фон только при включённой настройке и установленном Scheduler;
  • импорт ставится в фон галочкой в форме импорта, независимо от настройки;
  • очистка токенов и черновиков выполняется по расписанию с момента установки MiniShop3, настройка её не включает и не выключает.

Программно настройку меняют через объект modSystemSetting:

php
$setting = $modx->getObject(\MODX\Revolution\modSystemSetting::class, 'ms3_use_scheduler');
$setting->set('value', 1);
$setting->save();

setOption() настройку не сохраняет

$modx->setOption('ms3_use_scheduler', true) меняет значение только в памяти текущего запроса — в базу не попадает ничего. Задачи Scheduler выполняются отдельным процессом по cron и такого значения не увидят.

Встроенные задачи ​

MiniShop3 регистрирует при установке четыре задачи:

ЗадачаТипИнтервалФайл
ms3_cleanup_tokensповторяющаяся+1 weekelements/tasks/cleanupTokens.php
ms3_cleanup_draftsповторяющаяся+1 dayelements/tasks/cleanupDrafts.php
ms3_csv_importодноразовая—elements/tasks/csvImport.php
ms3_send_notificationодноразовая—elements/tasks/sendNotification.php

Интервал — это строка для функции PHP strtotime(), она хранится в поле interval задачи как есть. После успешного запуска Scheduler передаёт её в strtotime() и планирует следующий запуск. Если строка не разбирается или даёт время в прошлом, в MODX Error Log попадает Invalid interval, и повторяющаяся задача больше не планируется.

ms3_cleanup_tokens ​

Удаляет записи с истёкшим сроком действия из таблицы токенов авторизации покупателей ms3_customer_tokens.

ms3_cleanup_drafts ​

Удаляет заказы со статусом «Черновик», созданные раньше периода из настройки ms3_delete_drafts_after.

Период задаётся любой строкой, понятной функции PHP strtotime(): -1 day, -2 weeks, -1 month, -1 year. Пустое значение (так поставляется по умолчанию) отключает автоудаление.

php
$setting = $modx->getObject(\MODX\Revolution\modSystemSetting::class, 'ms3_delete_drafts_after');
$setting->set('value', '-2 weeks');
$setting->save();

ms3_csv_import ​

Импортирует товары из CSV. Режим выбирает человек: в форме импорта есть переключатель «синхронно или в фоне», и фоновый режим ставит задачу в очередь Scheduler.

Настройка ms3_import_sync_limit (по умолчанию 300 строк) на выбор не влияет напрямую: когда в файле строк больше, форма показывает переключатель режима, а если Scheduler не установлен — предупреждение, что файл велик для синхронного прохода. Сам импорт в очередь не уходит, пока переключатель не выставлен.

Передаваемые параметры:

php
$scriptProperties = [
    'file' => 'path/to/file.csv',  // Путь к файлу относительно MODX_BASE_PATH
    'mapping' => [...],            // Соответствие колонок полям товара
    'fields' => [...],             // Прежний формат соответствия, для совместимости
    'update' => false,             // Обновлять существующие товары
    'key' => 'article',            // Поле, по которому ищется существующий товар
    'delimiter' => ';',            // Разделитель колонок
    'skip_header' => false,        // Пропустить первую строку
    'debug' => false,              // Подробный лог вместо записи в базу
    'import_id' => 'import_...',   // Идентификатор прогона, ставится процессором
];

ms3_send_notification ​

Отправляет уведомления, не блокируя основной запрос. Полезно для медленных каналов — например, для Telegram.

Уведомление уходит в очередь, когда выполнены оба условия: настройка ms3_use_scheduler включена и сервис scheduler зарегистрирован. Иначе уведомление отправляется сразу, в том же запросе. Задержка берётся из настроек самого уведомления (поле «Задержка» для статуса и типа получателя); при нулевой задержке запуск ставится на +1 second.

Передаваемые параметры:

php
$scriptProperties = [
    'notification_class' => 'MiniShop3\Notifications\Order\StatusChangedNotification',
    'order_id' => 123,
    'channel' => 'telegram',         // имя канала: email или telegram
    'recipient_type' => 'manager',   // customer или manager
    'recipient' => [...],            // данные получателя для канала
    'notification_data' => [...],    // снимок данных уведомления
];

Задача восстанавливает уведомление по имени класса. Для StatusChangedNotification она берёт идентификаторы статусов из notification_data (new_status.id, old_status.id) и заново загружает объекты статусов; если нового статуса нет в базе, запуск завершается ошибкой.

Каналы. В поставке зарегистрированы два: email и telegram. Класс SmsChannel в коде есть, но сам не подключается — свой канал регистрируют плагином на событие msOnRegisterNotificationChannels, которому приходит параметр manager:

php
$manager = $modx->getOption('manager', $scriptProperties);
$manager->registerChannel(new \MyPackage\Notifications\SmsChannel($modx));

Мониторинг задач ​

Через админку ​

Дополнения → Scheduler — три вкладки: «Задания» (зарегистрированные задачи), «Запланированные запуски» и «Прошедшие запуски».

Через API ​

У задачи нет метода, отдающего последний запуск, — запуски читаются запросом к sTaskRun:

php
/** @var \Scheduler $scheduler */
$scheduler = $modx->services->get('scheduler');

$task = $scheduler->getTask('minishop3', 'ms3_cleanup_tokens');

$c = $modx->newQuery('sTaskRun');
$c->where(['task' => $task->get('id')]);
$c->sortby('executedon', 'DESC');
$c->limit(1);

/** @var \sTaskRun|null $lastRun */
$lastRun = $modx->getObject('sTaskRun', $c);

if ($lastRun) {
    echo $lastRun->get('status');          // 0 ждёт, 1 выполняется, 2 успех, 3 ошибка
    echo $lastRun->get('executedon');      // метка времени запуска
    echo $lastRun->get('processing_time'); // длительность в секундах
    echo $lastRun->get('message');         // сообщение задачи

    if ($lastRun->hasErrors()) {
        print_r($lastRun->get('errors'));
    }
}

Числа статуса соответствуют константам sTaskRun::STATUS_SCHEDULED, STATUS_EXECUTING, STATUS_SUCCESS и STATUS_FAILURE.

Ручной запуск задач ​

Через админку ​

  1. Откройте Дополнения → Scheduler → Задания.
  2. Найдите задачу (namespace: minishop3).
  3. В контекстном меню выберите Запланировать запуск.

Запуск встанет в очередь. Один проход cron берёт столько запусков, сколько указано в настройке Scheduler scheduler.tasks_per_run — по умолчанию один, поэтому при непустой очереди запуск может подождать несколько проходов.

Через PHP ​

php
/** @var \Scheduler $scheduler */
$scheduler = $modx->services->get('scheduler');

// Получить задачу
$task = $scheduler->getTask('minishop3', 'ms3_cleanup_tokens');

// Поставить в очередь — задачу подхватит ближайший запуск cron
$task->schedule('+1 minute');

// Для задач с параметрами они передаются вторым аргументом
$task->schedule('+1 minute', ['import_id' => 'import_123']);

Синхронного запуска у задачи нет: schedule() только ставит запуск в очередь, а выполняет его cron-скрипт Scheduler.

Создание собственных задач ​

Типы задач, передача данных и правила возврата результата описаны в документации Scheduler: Создание задания и Разработка заданий. Ниже — только то, что касается задач рядом с MiniShop3.

Регистрация задачи ​

php
/** @var \Scheduler $scheduler */
$scheduler = $modx->services->get('scheduler');

// Создать задачу
$task = $modx->newObject('sTask');
$task->fromArray([
    'class_key' => 'sFileTask',
    'namespace' => 'mypackage',
    'reference' => 'my_custom_task',
    'content' => 'elements/tasks/myTask.php',  // Относительно core-пути namespace
    'description' => 'My custom MiniShop3 task',
    'recurring' => true,
    'interval' => '+1 hour',
]);
$task->save();

// Запланировать первый запуск
$task->schedule('+1 minute');

Файл задачи ​

Scheduler подключает файл через include и даёт в нём четыре переменные: $modx, $task, $run и $scriptProperties (данные из второго аргумента schedule()). Возвращённое значение попадает в результат запуска.

php
<?php
/**
 * @var modX $modx
 * @var sFileTask $task
 * @var sTaskRun $run
 * @var array $scriptProperties
 */

// Получение сервиса MiniShop3
$ms3 = $modx->services->get('ms3');

// Ваша логика
try {
    // ... выполнение задачи ...

    $modx->log(modX::LOG_LEVEL_INFO, "[myTask] Completed successfully");
    return true;
} catch (\Exception $e) {
    $run->addError('exception', ['error' => $e->getMessage()]);
    return false;
}

Первый аргумент addError() — тип ошибки, подробности передаются массивом вторым аргументом. Именно этот вызов решает судьбу запуска: запуск получает статус «ошибка», если в нём есть хотя бы одна запись об ошибке. Возврат false сам по себе статус не меняет — возвращённое значение попадает в поле message. Подробнее — Регистрация ошибок в Scheduler.

Связанные настройки ​

НастройкаПо умолчаниюОписание
ms3_use_schedulerfalseОтправлять уведомления через очередь Scheduler
ms3_delete_drafts_afterпустоПериод хранения черновиков, формат strtotime()
ms3_import_sync_limit300Число строк, после которого форма импорта предлагает фоновый режим

Со стороны Scheduler на поведение задач влияют scheduler.tasks_per_run, scheduler.recurring_on_failure и настройки писем о сбоях.

Устранение проблем ​

Задачи не выполняются ​

Проверьте:

  • настроен ли cron для Scheduler — как его настроить;
  • читает ли веб-сервер файлы задач;
  • что пишет Scheduler в MODX Error Log.

Если очередь длинная, запуск ждёт своего прохода: по умолчанию cron берёт одну задачу за раз (scheduler.tasks_per_run).

Повторяющиеся задачи не перезапускаются ​

Чаще всего причина в том, что прошлый запуск завершился с ошибкой: следующий запуск после неудачи не планируется, в лог идёт stopped due to failure. Чтобы цикл продолжался и после ошибок, включите настройку Scheduler scheduler.recurring_on_failure — по умолчанию она выключена.

Остальное, что стоит проверить:

  • версию Scheduler — нужна 1.8.0 или выше;
  • поле recurring в настройках задачи;
  • значение interval — строка, которую не разбирает strtotime(), даёт Invalid interval и останавливает цикл.

Ошибки в задачах ​

Логи задач:

  • MODX Error Log (core/cache/logs/error.log);
  • вкладка «Прошедшие запуски» в Scheduler — у каждого запуска видны сообщение и список ошибок.

Записи об ошибках хранятся в поле errors запуска: это массив, где у каждой записи есть type (первый аргумент addError()), timestamp и переданные подробности.