Версия: 3.x
Планировщик заданий cron

Внутренний планировщик ReadyScript позволяет модулям запускать собственные задачи в необходимое время или с необходимым интервалом. Для работы внутреннего планировщика необходимо на сервере настроить ежеминутный запуск файла путь к корневой папке сайта/core/cron/cron.php. Подробная инструкция по настройке представлена здесь.

Установка задачи для планировщика

В момент запука внутреннего планировщика cron.php в ReadyScript генерируется событие с названием "cron". Таким образом все подписчики на это событие получают по очереди возможность выполнить собственный код. Каждый обработчик события самостоятельно решает необходимо ли ему выполнять задание во время запуска или нет, опираясь на поступившие в событие параметры. В событие передается массив с тремя параметрами:

  • last_time - число, timestamp предыдущего запуска
  • current_time - число, timestamp текущего запуска
  • minutes - массив, номер минуты текущего запуска + список номеров минут для которых был пропущен запуск.

Рассмотрим различные примеры запуска cron.php:

  1. cron.php запускается первый раз за всю историю, 26.01.2016 в 16:00:00. Обработчикам будут переданы следующие параметры:
    • last_time = 1453813140 (26.01.2016 15:59:00)
    • current_time = 1453813200 (26.01.2016 16:00:00)
    • minutes = [960]
  2. cron.php запускается 26.01.2016 в 16:01:00, предыдущий запуск был 26.01.2016 16:00:00. Обработчики получат следующие параметры:
    • last_time = 1453813200 (26.01.2016 16:00:00)
    • current_time = 1453813260 (26.01.2016 16:01:00)
    • minutes = [961]
  3. cron.php запускается 26.01.2016 в 16:10:00, предыдущий запуск был 26.01.2016 16:01:00. Обработчикам будут переданы следующие параметры:
    • last_time = 1453813260 (26.01.2016 16:01:00)
    • current_time = 1453813800 (26.01.2016 16:10:00)
    • minutes = [962,963,964,965,966,967,968,969,970]
  4. cron.php запускается в 27.01.2016 00:00:00, предыдущий запуск был 26.01.2016 23:58:00. Обработчикам будут переданы следующие параметры:
    • last_time = 1453841880 (26.01.2016 23:58:00)
    • current_time = 1453842000 (27.01.2016 00:00:00)
    • minutes = [1439,0]

Как видно на примере N3, обработчик все равно получит все минуты в массиве, которые бы он получил, если бы cron запускался ежеминутно.

Три параметра, передаваемые обработчику позволяют легко организовывать любое расписание для запуска, будь то фиксированная дата или интервал. В сутки обработчики гарантировано получат в параметре minutes числа от 0 до 1439, что соответствует количеству минут в сутках.

Планировщик построен таким образом, что при любом количестве запусков файла crop.php в сутки, внутри ReadyScript все модули будут получать необходимые сведения для выполнения задач, как если бы планировщик выполнялся, как положено, раз в минуту. Если планировщик не был запущен в назначенное время, то задача выполнится при следующем выполнении cron.php.

Следует учитывать, что выполнение задания может занимать время, превышающее 1 минуту, соответственно следующий запуск планировщика будет выполнен только после полного завершения текущей сессии выполнения планировщика. Для защиты от двойного запуска, планировщик создает файл с именем cron в папе /storage/locks/. Данный файл автоматически удаляется в случае успешного завершения планировщика.

Теперь рассмотрим на примерах различные случаи формирования расписаний.

  • Необходимо установить запуск задания один раз в пять минут.
namespace ModuleName\Config;
// Класс содержит обработчики событий, на которые подписан модуль
class Handlers extends \RS\Event\HandlerAbstract
{
function init()
{
$this->bind('cron'); //Подписываемся на событие cron
}
//Обработчик события
public static function cron($params)
{
foreach($params['minutes'] as $minute) {
if (($minute % 5) == 0) { //Если остаток от деления номера минуты на 5 равен 0
//Задание будет запущено 1 раз в 5 минут
}
}
}
}
  • Необходимо установить запуск задания в 3:00, в 18:00 и в 21:00 каждый день
...
class Handlers extends \RS\Event\HandlerAbstract
{
...
//Обработчик события
public static function cron($params)
{
foreach($params['minutes'] as $minute) {
if (in_array($minute, array(180, 1080, 1260))) {
//Задание будет запущено в 3:00 - 180 минута от начала суток (3 * 60 = 180)
//Задание будет запущено в 18:00 - 1080 минута от начала суток (18 * 60 = 1080)
//Задание будет запущено в 21:00 - 1260 минута от начала суток (21 * 60 = 1260)
}
}
}
}
  • Необходимо установить запуск задания 30.01.2020 в 15:40:00
...
class Handlers extends \RS\Event\HandlerAbstract
{
...
//Обработчик события
public static function cron($params)
{
$need_time = strtotime('2020-01-30 15:40:00'); //Получаем timestamp для требуемой даты, времени.
if ($params['last_time'] < $need_time && $need_time <= $params['current_time']) {
//Задание будет выполнено в намеченную дату $need_time
}
}
}
Заметки
Следует учитывать, что cron.php запускается из командной строки, соответственно во время обработки события нельзя полагаться на автоматическое определение ID текущего сайта. Функция RS::Site::Manager::getSiteId() - будет возвращать id сайта по-умолчанию. Функция RS::Site::Manager::getAdminCurrentSite() - будет возвращать false Если в момент обработки события cron, вам необходимо записывать в базу объекты, поддерживающие мультисайтовость, то идентификатор сайта следует указывать у такого объекта явно.

Проверка состояния планировщика

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

Проверить работает ли внутренний планировщик можно с помощью вызова метода RS::Cron::Manager::isCronWork.

Пример:

//Получаем объект планировщика
$cron_manager = \RS\Cron\Manager::obj();
if ($cron_manager->isCronWork()) {
//cron работает
} else {
//cron не работает
//(не включен в настройках системы или не настроен на сервере запуск файла cron.php)
}

В разделе Управление → Настройка системы имеется возможность отключить выполнение заданий планировщика, а также удалить файл блокировки. Удаление файла блокировки следует производить вручную в момент разработки, если cron.php прекратил свою работу не запланировано, например, в случае возникновения исключения или фатальной ошибки.

Заметки
Система проигнорирует файл блокировки /storage/locks/cron, если он был создан более чем 1 час назад.

Рекомендации по использованию фоновых задач

  • Рекомендуем выводить предупреждение о неработоспособности планировщика в вашем модуле, если он требуется для корректной работы вашего модуля
  • Время выполнения задания не должно превышать 1 час, желательно укладываться в 1 секунду.
  • Не делайте в обработчике события cron запросы к БД каждую минуту, если задача того не требует. (берегите ресурсы клиентов)