TL;DR
Агенты Bitrix не выполняются, а крон-сервисы вроде cron-job.org валятся по таймауту? Классика для shared-хостинга. Корень проблемы — стандартный agent.php не рассчитан на долгие задачи и жёсткие лимиты внешних запросов.
- Меняем точку входа. Вместо
/bitrix/agent.phpиспользуем отдельный скрипт, который не зависит от ядра Bitrix. Создаём в корне сайта файлcron_agent.php:
<?php
$_SERVER["DOCUMENT_ROOT"] = __DIR__;
require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Отключаем лимит времени выполнения
set_time_limit(0);
// Включаем буферизацию, чтобы не сбрасывать данные каждый раз
ob_start();
// Запускаем только агенты, требующие выполнения прямо сейчас
CAgent::CheckAgents();
// Сбрасываем буфер и завершаем
ob_end_flush();
?>
Настраиваем крон. В панели хостинга (или через cron-job.org) ставим вызов этого файла раз в минуту. Важно: таймаут запроса должен быть не меньше 120 секунд, а лучше — 300. На Beget это настраивается в разделе «Задания по расписанию».
Убираем штатный механизм. В админке Bitrix («Настройки» → «Настройки модулей» → «Главный модуль» → «Агенты») отключаем выполнение агентов на хите — снимаем галочку «Выполнять агенты на посетителях». Иначе они будут конфликтовать и дублироваться.
Проверяем логи. После настройки заглядываем в /bitrix/managed_cache/agent.log. Если файл пустой — всё работает корректно. Если там ошибки — смотрим, какой конкретно агент падает, и разбираемся с ним отдельно.
Финальный нюанс. Даже с этим решением тяжёлые агенты (полная переиндексация) могут висеть по 5-10 минут. На shared-хостинге это норма. Решение — разбивать большие задачи на порции по 100-200 элементов через LAST_EXEC и NEXT_EXEC в таблице b_agent. Так ни один запуск не превысит разумный лимит.
Симптом
У вас именно эта проблема, если агенты в админке (Настройки → Настройки модулей → Главный модуль → Агенты) висят в статусе «Ожидает» с LAST_EXEC старше суток, а /bitrix/managed_cache/agent.log пустой — значит, штатный механизм запуска агентов при каждом хите не срабатывает, а внешний крон-сервис (cron-job.org) не успевает обработать задачу за 30 секунд. На shared-хостинге Beget с PHP 8.2 и Bitrix 24.0.796 системного cron нет, поэтому единственный способ запуска — через посещение сайта. Если трафика нет, агенты не стартуют. Второй симптом — попытка дёргать /bitrix/agent.php?ID=... через сторонние сервисы валится по timeout на тяжёлых операциях (полная переиндексация поиска), потому что стандартный agent.php за 30 секунд не успевает перебрать все записи и уходит в таймаут.
Ключевое отличие от «нормальной» работы на VPS или выделенном сервере — отсутствие возможности задать интервал выполнения агентов через системный crontab. На shared-хостинге вы не можете поставить */1 * * * * php /path/to/bitrix/modules/main/tools/cron_agents.php, а сторонние HTTP-крон-сервисы ограничены таймаутом соединения (обычно 30–60 секунд). Bitrix в своей штатной логике пытается выполнить все агенты с просроченным NEXT_EXEC за один вызов agent.php, и если один агент (например, переиндексация) висит 20 секунд, остальные просто не успевают стартовать. Это как пытаться загрузить 10 файлов по одному каналу — пока грузится большой, мелкие ждут и тоже уходят в таймаут.
Единственный рабочий вариант на shared-хостинге — не использовать прямой вызов agent.php, а настроить выполнение агентов через внешний сервис, который вызывает cron_agents.php с возможностью разбивки на пакеты. Либо переключиться на хостинг с поддержкой системного cron. Без этого агенты будут либо простаивать, либо падать по таймауту при первой же тяжёлой задаче.
Причина
Многие думают: «Ну, стандартный крон на shared-хостинге — это же просто. Поставил вызов /bitrix/agent.php раз в минуту, и агенты полетят». Я сам так думал, пока не упёрся в таймауты в 30 секунд на cron-job.org и не увидел в админке статус «Ожидает» для всех агентов. Логика кажется железной: дёргаем скрипт — он запускает агенты. Но всё сложнее.
Проблема вот в чём: стандартный /bitrix/agent.php — это не «крон-обработчик», а однопоточный скрипт, который выполняет агенты последовательно, один за другим. Когда ему попадается тяжёлая задача — полная переиндексация поиска, массовое обновление цен — он просто висит, пока не упадёт по таймауту внешнего сервиса. На Beget с Bitrix 24.0.796 и PHP 8.2 это выглядело так: cron-job.org отправлял GET-запрос, скрипт начинал выполнять агент с ID=..., через 30 секунд сервис обрывал соединение, а агент оставался в статусе «Ожидает» с пометкой «Выполняется». Логи /bitrix/managed_cache/agent.log были пустыми — скрипт даже не успевал записать ошибку. Это не баг, а архитектурное ограничение: agent.php не умеет ставить агентов в очередь и не возвращает управление, пока не закончит. На shared-хостинге без системного cron штатный механизм превращается в лотерею — лёгкие задачи проскакивают, тяжёлые вечно висят.
На практике это значит одно: если у вас на проекте есть хоть один долгий агент (перестроение поискового индекса, обновление каталога из 1С, генерация sitemap), полагаться на стандартный вызов agent.php через внешние сервисы — путь к постоянным сбоям. Тут мнения расходятся: кто-то ставит свой крон-демон на VPS, кто-то выносит агенты в отдельный PHP-скрипт с set_time_limit(0). Но для shared-хостинга честное решение только одно — переключить BX_CRONTAB_SUPPORT и переписать логику выполнения агентов под пакетный режим, чтобы один вызов обрабатывал не больше одного-двух агентов за раз.
Решение
Раньше казалось, что для работы агентов на shared-хостинге достаточно просто дёргать /bitrix/agent.php раз в минуту через любой внешний крон-сервис. Логика простая: есть скрипт, есть вызов — агенты выполняются. Но на практике этот подход ломался каждый раз, когда агентам требовалось больше 30 секунд на выполнение.
Переломный момент наступил, когда Bitrix перешёл на PHP 8.x и ужесточил требования к выполнению длительных операций. Внешние сервисы вроде cron-job.org жёстко обрезают запросы по таймауту (обычно 30 секунд), а штатный механизм агентов без системного крона полагается только на хиты посетителей. Если трафика нет — агенты просто висят в статусе «Ожидает» сутками. На проекте с Bitrix 24.0.796 под PHP 8.2 на хостинге Beget это вылилось в то, что полная переиндексация поиска ни разу не завершилась: агент запускался, через 30 секунд получал 502 ошибку, и LAST_EXEC не обновлялся. Лог /bitrix/managed_cache/agent.log оставался пустым — скрипт не успевал даже начать запись.
Сегодня правильное решение — не полагаться на внешние HTTP-вызовы для длительных задач, а использовать системный cron в обход веб-сервера. На shared-хостинге это делается через PHP-запуск из командной строки: php -f /home/user/www/bitrix/agent.php. В админке Bitrix (Настройки → Настройки модулей → Главный модуль → Агенты) переключаем режим на «Системный cron» и прописываем в crontab вызов раз в минуту. Критично: сам скрипт agent.php не должен выполняться через HTTP — только через CLI, иначе таймауты никуда не денутся. Для агентов с высокой нагрузкой (переиндексация, обновление поискового индекса) дополнительно ставим set_time_limit(0) в начале agent.php.
Дальше — переход на выделенный сервер или VPS, где можно настроить supervisor для агентов. На shared-хостинге это предел возможностей, но он закрывает 95% проблем с зависшими задачами. Оставшиеся 5% — это агенты, которые пишут напрямую в файловую систему с блокировками. Их придётся переписывать под очередь через Bitrix\Main\Application::getConnection()->queryExecute().
Подводные камни
Раньше считалось, что если поднять cron на shared-хостинге — задача решена. Ставишь вызов /bitrix/agent.php раз в минуту через любой бесплатный сервис вроде cron-job.org, и агенты Bitrix работают как часы. Этот подход кочевал из статьи в статью, и многие на нём обжигались.
Переломный момент наступил, когда Bitrix усложнил логику работы агентов, а PHP на shared-хостингах перешёл на версию 8.x с более строгими лимитами. Старый трюк «дёрнуть agent.php» сломался о две вещи. Первая — таймаут внешнего крон-сервиса. Cron-job.org режет запросы на 30 секунд, а типовой агент полной переиндексации поиска на каталоге в 50 000 товаров спокойно висит 2–3 минуты. Вторая — сам agent.php в стандартном режиме не запускает «долгие» агенты: он берёт только те, чей интервал меньше 60 секунд, и выполняет их последовательно. Если один завис — очередь встала. В конфигурации beget + Bitrix 24.0.796 + PHP 8.2 это привело к тому, что агенты висели в статусе «Ожидает» сутками, а LAST_EXEC не обновлялся. Лог /bitrix/managed_cache/agent.log оставался пустым, хотя формально вызов происходил.
Сейчас правильный подход выглядит иначе. Мы настраиваем не внешний cron, а системный, даже на shared-хостинге. Beget, как и большинство современных хостеров, даёт доступ к cron через панель управления — это не «системный» в смысле root, но его таймауты управляются самим PHP, а не внешним сервисом. Второе — обязательно включаем константу BX_CRONTAB_SUPPORT в bitrix/.settings.php. Без неё agent.php работает в режиме «по запросу», а не в фоне. Третье — для долгих агентов (переиндексация, обновление цен) ставим отдельный вызов cron_events.php с интервалом в 5 минут, а не раз в минуту. Это снижает нагрузку и даёт PHP время выполнить тяжёлую операцию без таймаута.
Дальше движение идёт в сторону полного отказа от agent.php. На новых проектах мы уже используем модуль «Крон» из Маркетплейса, который запускает агенты через системный планировщик напрямую, минуя веб-сервер. Это снимает проблему таймаутов и зависимости от посещаемости сайта окончательно.
FAQ
«А что, если я просто поставлю вызов /bitrix/agent.php раз в минуту через внешний сервис?» — спрашивает каждый второй клиент. И мы сами так делали. Пока не упёрлись в стену: агенты с тяжёлой нагрузкой просто не успевают отработать за 30 секунд. Сервис типа cron-job.org даёт таймаут — и всё, агент повис в статусе «Ожидает».
Почему так? agent.php — это не демон, а обычный скрипт, который живёт ровно столько, сколько длится HTTP-запрос. Если полная переиндексация поиска требует минуты работы — скрипт убьют по таймауту, агент не выполнится, и LAST_EXEC останется вчерашним. Логи пустые, статус «Ожидает» — классика.
Выход — не дёргать скрипт, а заставить Bitrix работать через системный cron. Даже на shared-хостинге. Смотрим: в файл /bitrix/php_interface/dbconn.php добавляем константу:
define('BX_CRONTAB_SUPPORT', true); // включаем cron-режим агентов
Дальше — сам cron. Если у вас Beget или аналог с панелью управления — ищите раздел «Cron». Если его нет — пишите в поддержку хостинга, просите доступ. Команда для крона:
* * * * * /usr/bin/php -f /home/user/public_html/bitrix/modules/main/tools/cron_agents.php
Замените путь на свой. Путь к PHP может отличаться — уточните в поддержке. Убедитесь, что файл cron_agents.php существует и доступен для чтения. После добавления задачи проверьте через минуту: статус агентов в админке должен смениться на «Выполняется» или «Готов». LAST_EXEC обновится.
А что, если хостинг не даёт системный cron? Тогда остаётся одно: переезжать на VPS или выделенный сервер. Shared-хостинг — это компромисс. Для Bitrix с агентами на пару сотен задач он просто не годится. И да — внешние крон-сервисы с таймаутом 30 секунд забудьте. Они бесполезны.
См. также
Видел сотни проектов, где агенты просто молча умирали на shared-хостинге. Самая частая картина: клиент ставит вызов /bitrix/agent.php раз в минуту через cron-job.org, агенты в админке висят сутками, а в логах — тишина. И всё потому, что стандартный agent.php без BX_CRONTAB_SUPPORT — декорация, а не рабочий инструмент.
Разложу на примере. Приходит клиент с Beget: сайт на Bitrix, посетителей днём с огнём, агенты не бегут. В админке — статус «Ожидает», LAST_EXEC старше суток. Он настроил cron-job.org дёргать /bitrix/agent.php?ID=... — и получил timeout 30 секунд на переиндексации. Проблема: agent.php без константы BX_CRONTAB_SUPPORT работает в режиме веб-запроса. Он выполняет агенты последовательно, по одному за вызов, и если агент тяжёлый (полная переиндексация поиска), он тупо не укладывается в лимиты внешнего сервиса. Решение — включить настоящий cron-режим. В bitrix/.settings.php добавляем секцию crontab с параметром support в true. После этого agent.php начинает работать иначе: при каждом вызове он запускает несколько агентов, контролирует время выполнения и корректно завершает сессию. На Beget это залетает без проблем — главное, чтобы в настройках хостинга был разрешён запуск PHP-скриптов через cron (обычно это есть). После включения проверяем лог /bitrix/managed_cache/agent.log. Он должен перестать быть пустым, и в админке статусы агентов начнут меняться на «Выполняется».
Мой совет: никогда не используйте agent.php «как есть» на shared-хостинге. Если нет доступа к системному cron — включайте BX_CRONTAB_SUPPORT через .settings.php. Только так агенты будут работать стабильно, когда посетителей нет, а таймауты внешних сервисов давят.