Администрирование
Cron и агенты
Рабочая справка по агентам и cron в коробочном Bitrix24: CAgent::AddAgent, RemoveAgent, CheckAgents, периодичность, cron_events.php и диагностика.
Агент — это отложенный PHP-вызов, который Битрикс запускает по расписанию. На боевых коробках агенты часто переводят на cron, чтобы они выполнялись стабильнее и не зависели от посещений сайта.
Общее понимание
Агенты используются для регулярных и отложенных задач внутри Битрикса.
Что такое агент
Агент — это строка PHP-кода, которую Битрикс хранит в таблице агентов и запускает, когда подходит время выполнения.
Обычно агент должен вернуть строку своего следующего вызова. Если агент вернёт пустую строку, он больше не будет планировать следующий запуск.
Ограничение от дублей
Агенты выполняются в однопоточном режиме. Если конкретный агент работает долго, система блокирует повторный запуск этого же агента, чтобы не запустить его второй раз параллельно.
Это не означает, что остановятся все агенты. Блокировка относится к проблемному агенту, а остальные агенты продолжают выполняться по своему расписанию.
Практический вывод: долгие задачи лучше дробить на части. Агент должен обработать небольшую порцию данных, сохранить прогресс и вернуть строку следующего запуска.
Cron и хиты
| Режим | Как работает |
|---|---|
| На хитах | Агенты проверяются при посещениях сайта. |
| На cron | Агенты запускаются системным расписанием сервера. |
Базово агенты могут запускаться на хитах. Поэтому запуск зависит от активности пользователей: если портал почти не открывают, возможны задержки.
Для коробочного Bitrix24 cron обычно настраивает администратор сервера. Важно, чтобы команда выполнялась от правильного пользователя, который имеет доступ к файлам проекта.
Периодический и непериодический запуск
У CAgent::AddAgent() параметр period влияет на расчёт
следующего запуска.
| period | Как считать |
|---|---|
Y | Следующий запуск считается от запланированного времени: предыдущее время запуска + интервал. |
N | Следующий запуск считается от фактического завершения: время окончания работы + интервал. |
Для тяжёлых обработчиков чаще удобнее непериодический режим N, чтобы
следующий запуск не планировался поверх долгого предыдущего выполнения.
Работа с агентами
Базовые операции: добавить, удалить, написать функцию агента и проверить список.
Добавить агент
Агент можно добавить через административный интерфейс или программно через
CAgent::AddAgent(). Программный вариант удобен при установке модуля.
<?php
use Bitrix\Main\Loader;
Loader::includeModule('main');
const MODULE_ID = 'itsolution.example';
/**
* Регистрирует агент модуля.
*/
function addExampleAgent(): int
{
$agent_id = \CAgent::AddAgent(
'\\Itsolution\\Example\\Agent\\ExampleAgent::run();',
MODULE_ID,
'N',
300,
'',
'Y',
''
);
return (int) $agent_id;
}
$agent_id = addExampleAgent();
echo $agent_id; Параметры AddAgent
Полный вызов AddAgent() позволяет указать модуль, интервал, активность,
сортировку, пользователя и проверку дублей.
<?php
const MODULE_ID = 'itsolution.example';
/**
* Добавляет агент с основными параметрами.
*/
function addExampleAgentWithParameters(): int
{
$agent_id = \CAgent::AddAgent(
'\\Itsolution\\Example\\Agent\\ExampleAgent::run();',
MODULE_ID,
'N',
3600,
'',
'Y',
'',
100,
false,
true
);
return (int) $agent_id;
}
$agent_id = addExampleAgentWithParameters();
echo $agent_id; | Параметр | Пример | Что означает |
|---|---|---|
| Функция | ExampleAgent::run(); | PHP-код, который должен выполниться. |
| Модуль | itsolution.example | Модуль, к которому относится агент. Для функции из общего init.php можно оставить пустую строку. |
| Периодичность | N или Y | N — следующий запуск после завершения. Y — от планового времени. |
| Интервал | 3600 | Интервал между запусками в секундах. |
| Дата проверки | '' | Дата, с которой агент нужно проверять. |
| Активность | Y | Запускать агент или нет. |
| Дата следующего запуска | '' | Когда агент должен выполниться в следующий раз. |
| Сортировка | 100 | Чем меньше значение, тем выше агент в списке. |
| Пользователь | false | Обычно системный агент выполняется без конкретного пользователя. |
| Проверка дубля | true | Не добавлять второй такой же агент повторно. |
Где хранить функцию агента
Функция агента должна быть доступна в момент запуска. Есть два нормальных варианта:
общий init.php или класс внутри модуля.
| Где лежит код | Что указывать в агенте |
|---|---|
/local/php_interface/init.php | Функция вида agentTest();, модуль можно оставить пустым. |
/local/modules/vendor.module/include.php | Указать ID модуля, чтобы Битрикс подключил модуль перед запуском агента. |
/local/modules/vendor.module/lib/Agent/ExampleAgent.php | Вызов статического метода, например Vendor\Module\Agent\ExampleAgent::run();. |
Для новых доработок лучше использовать класс модуля. Так проще подключать зависимости, регистрировать агент при установке модуля и удалять его при удалении.
<?php
/**
* Простой агент из init.php.
*/
function agentTest(): string
{
// Здесь основной код агента
return 'agentTest();';
} Удалить агент
<?php
const MODULE_ID = 'itsolution.example';
/**
* Удаляет агент модуля.
*/
function removeExampleAgent(): void
{
\CAgent::RemoveAgent(
'\\Itsolution\\Example\\Agent\\ExampleAgent::run();',
MODULE_ID
);
}
removeExampleAgent();
Удаление агента обычно вызывают при удалении модуля в uninstallEvents()
или отдельном методе uninstallAgents().
Функция агента
<?php
namespace Itsolution\Example\Agent;
use Bitrix\Main\Diag\Debug;
use Bitrix\Main\Loader;
class ExampleAgent
{
/**
* Выполняет агент и возвращает следующий вызов.
*/
public static function run(): string
{
try {
Loader::includeModule('crm');
Debug::dumpToFile(
[
'message' => 'Агент выполнен',
'date' => date('Y-m-d H:i:s'),
],
'example_agent',
'/local/logs/example_agent.log'
);
} catch (\Throwable $exception) {
Debug::dumpToFile(
[
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
],
'example_agent_error',
'/local/logs/example_agent.log'
);
}
return '\\Itsolution\\Example\\Agent\\ExampleAgent::run();';
}
} Если агент должен повторяться, метод возвращает строку следующего вызова. Если нужно остановить агент, метод возвращает пустую строку.
Ограничить количество запусков
Если функция агента вернёт пустую строку, агент больше не будет планировать следующий запуск. На этом можно сделать ограничение по количеству выполнений.
<?php
/**
* Выполняет агент ограниченное количество раз.
*/
function runLimitedAgent(int $limit = 5): string
{
if ($limit <= 0) {
return '';
}
// Здесь основной код агента
$next_limit = $limit - 1;
return 'runLimitedAgent(' . $next_limit . ');';
} Такой вариант удобен для временных служебных задач: обработать несколько пачек данных и автоматически остановиться.
Изменить интервал из агента
Интервал следующего запуска можно изменить прямо из функции агента через глобальную
переменную $GLOBALS['pPERIOD']. Это повлияет на ближайшее планирование
после текущего выполнения.
<?php
/**
* Меняет следующий интервал запуска агента.
*/
function runAgentWithDynamicInterval(): string
{
$has_heavy_load = false;
if ($has_heavy_load) {
$GLOBALS['pPERIOD'] = 3600;
} else {
$GLOBALS['pPERIOD'] = 300;
}
// Здесь основной код агента
return 'runAgentWithDynamicInterval();';
} Если нужно изменить постоянное значение интервала в записи агента, можно обновить сам агент. Следующий запуск при этом может пройти ещё по старому расписанию, а последующие — уже по новому интервалу.
<?php
/**
* Меняет постоянный интервал агента.
*/
function updateAgentInterval(int $agent_id, int $interval): bool
{
if ($agent_id <= 0 || $interval <= 0) {
return false;
}
return (bool) \CAgent::Update(
$agent_id,
[
'AGENT_INTERVAL' => $interval,
]
);
}
$is_updated = updateAgentInterval($agent_id, 3600);
var_dump($is_updated); Проверить агенты в базе
<?php
use Bitrix\Main\Application;
/**
* Получает агенты модуля.
*/
function fetchModuleAgents(string $module_id): array
{
$connection = Application::getConnection();
$sql_helper = $connection->getSqlHelper();
$safe_module_id = $sql_helper->forSql($module_id);
$agents = [];
$result = $connection->query("
SELECT
ID,
MODULE_ID,
NAME,
ACTIVE,
AGENT_INTERVAL,
NEXT_EXEC,
LAST_EXEC,
RUNNING,
RETRY_COUNT
FROM b_agent
WHERE MODULE_ID = '{$safe_module_id}'
ORDER BY ID ASC
");
while ($agent = $result->fetch()) {
$agents[] = $agent;
}
return $agents;
}
$agents = fetchModuleAgents('itsolution.example');
print_r($agents); Если агент выполняется без ошибок и зависаний, в списке должна обновляться дата последнего и следующего запуска. Если растёт количество попыток или агент зависает, нужно смотреть лог функции агента.
Cron
Команда cron зависит от окружения, версии PHP и пути до проекта.
Пример команды cron
Типовая команда для BitrixVM-подобного окружения:
*/1 * * * * /usr/bin/php -f /home/bitrix/www/bitrix/php_interface/cron_events.php
Добавлять её лучше в crontab пользователя, от которого работает проект, например
bitrix.
crontab -u bitrix -e Частичный перевод на cron
При частичном переводе часть логики остаётся на хитах, а часть выполняется через cron. Система продолжит запускать агенты при посещениях, а cron будет запускать свою часть фоновых задач.
<?php
/**
* Включает режим частичного использования cron для агентов.
*/
function enablePartialAgentCron(): void
{
COption::SetOptionString('main', 'agents_use_crontab', 'Y');
}
enablePartialAgentCron();
echo COption::GetOptionString('main', 'agents_use_crontab', 'N'); После этого нужно добавить задание cron на сервере. Путь до сайта заменить на свой.
*/10 * * * * /usr/bin/php -f /home/bitrix/www/bitrix/modules/main/tools/cron_events.php Полный перевод на cron
Полный перевод нужен, когда агенты не должны зависеть от посещаемости сайта. В этом режиме проверка агентов на хитах отключается, а запуск выполняет серверный cron.
<?php
/**
* Отключает проверку агентов на хитах.
*/
function disableHitAgentCheck(): void
{
COption::SetOptionString('main', 'agents_use_crontab', 'N');
COption::SetOptionString('main', 'check_agents', 'N');
}
disableHitAgentCheck();
echo COption::GetOptionString('main', 'agents_use_crontab', 'N');
echo COption::GetOptionString('main', 'check_agents', 'Y');
В /bitrix/php_interface/dbconn.php убирают прямое определение
BX_CRONTAB_SUPPORT и BX_CRONTAB, а вместо него оставляют
условие:
if (!(defined('CHK_EVENT') && CHK_EVENT === true)) {
define('BX_CRONTAB_SUPPORT', true);
}
Затем создают файл /bitrix/php_interface/cron_events.php.
<?php
$_SERVER['DOCUMENT_ROOT'] = realpath(dirname(__FILE__) . '/../..');
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', true);
define('BX_NO_ACCELERATOR_RESET', true);
define('CHK_EVENT', true);
define('BX_WITH_ON_AFTER_EPILOG', true);
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
@set_time_limit(0);
@ignore_user_abort(true);
CAgent::CheckAgents();
define('BX_CRONTAB_SUPPORT', true);
define('BX_CRONTAB', true);
if (CModule::IncludeModule('sender')) {
\Bitrix\Sender\MailingManager::checkPeriod(false);
\Bitrix\Sender\MailingManager::checkSend();
}
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/tools/backup.php';
CMain::FinalActions(); После этого файл добавляют в cron. На BitrixVM-подобном окружении команда может выглядеть так:
*/1 * * * * /usr/bin/php -f /home/bitrix/www/bitrix/php_interface/cron_events.php
Путь /home/bitrix/www нужно заменить на путь к своему сайту. Команду лучше
запускать от пользователя, которому принадлежат файлы проекта.
Вернуть запуск на хитах
Если нужно вернуть стандартное поведение, можно удалить или сбросить настройки
agents_use_crontab и check_agents, убрать изменения из
dbconn.php и очистить управляемый кеш.
<?php
/**
* Возвращает проверку агентов на хитах.
*/
function enableHitAgentCheck(): void
{
COption::RemoveOption('main', 'agents_use_crontab');
COption::RemoveOption('main', 'check_agents');
}
enableHitAgentCheck(); После возврата лучше проверить несколько агентов в административном списке: должна обновляться дата последнего и следующего запуска.
Проверка руками
Проверить cron можно запуском команды от пользователя проекта:
sudo -u bitrix /usr/bin/php -f /home/bitrix/www/bitrix/php_interface/cron_events.php Если команда не выполняется руками, cron тоже нормально работать не будет. Сначала нужно исправить путь к PHP, права пользователя или ошибку в PHP-коде.
Проверить запуск агентов можно и из PHP:
<?php
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
/**
* Принудительно проверяет агенты.
*/
function runAgentsCheck(): void
{
\CAgent::CheckAgents();
}
runAgentsCheck();
echo 'Agents checked'; Логирование cron
На время проверки можно направить вывод cron в файл.
*/1 * * * * /usr/bin/php -f /home/bitrix/www/bitrix/php_interface/cron_events.php >> /home/bitrix/cron_events.log 2>&1 После диагностики лучше не оставлять бесконечно растущий лог без ротации.
Источники
- Официальная документация: агенты и фоновые задачи
- Официальная документация: CAgent
- Официальная документация: CAgent::AddAgent
- Официальная документация: CAgent::RemoveAgent
- Официальная документация: CAgent::Update
- Официальный курс: агенты
- Официальный курс: запуск агентов из cron
- Официальная документация: Debug
- Bitrix24: Книга разработчика — Агенты