БесплатноБесплатный прототип ключевой страницы и черновик ТЗ при старте проекта

Агенты, cron и фоновые задачи в 1С-Битрикс

Агенты, cron и фоновые задачи в 1С-Битрикс: регламентные задачи, два режима запуска, очередь и надёжность

Почти на любом интернет-магазине есть работа, которую нельзя привязать к нажатию кнопки посетителем: разобрать очередь писем, забрать заказы и остатки из 1С, пересчитать бонусы, обновить курсы валют, почистить временные файлы, сгенерировать выгрузку для маркетплейса. Всё это — задачи по расписанию. В 1С-Битрикс за них отвечают агенты — встроенный в ядро механизм периодических задач. Но у агентов есть коварная особенность: по умолчанию они часто запускаются «на хитах», то есть на запросах реальных посетителей, — и тогда ночью на малопосещаемом сайте ваш обмен с 1С может просто не сработать, а тяжёлый агент замедлит страницу живому человеку.

Эта статья — практическая карта регламентных задач в Битриксе. Разберём, что такое агенты и как устроен их жизненный цикл (интервал, next_exec, признак периодичности), чем режим «агенты на хитах» отличается от «агентов на cron» и почему для продакшена почти всегда выбирают cron. Покажем настройку cron через bitrix/php_interface и cron_events.php, пошаговый перевод агентов на cron, создание агента через CAgent::AddAgent, идемпотентность и блокировки от повторного запуска, очередь писем и почтовые события по расписанию, обмен с 1С, вынос тяжёлых фоновых задач в отдельный процесс и очередь, пул задач и параллельность, а также отладку «агент не запускается» и мониторинг. Материал — выжимка из нашей практики поддержки проектов на 1С-Битрикс, где стабильность фоновых задач напрямую влияет на то, вовремя ли уходят письма и обновляются ли остатки.

Коротко

  • Агенты — периодические задачи в ядре Битрикса: функция + модуль + интервал + время следующего запуска (next_exec). Через них идут рассылки, обмен, пересчёты и чистки.
  • Есть два режима запуска: на хитах (зависит от трафика, тормозит посетителя) и на cron (по расписанию ОС, независимо от посетителей). Для продакшена — cron.
  • Перевод на cron: отключить агенты на хитах в bitrix/php_interface и добавить в crontab регулярный вызов cron_events.php.
  • Тяжёлые фоновые задачи не гоняют в агенте на хите — их порционируют или выносят в отдельный процесс/очередь; агент лишь ставит задание.
  • Надёжность — это идемпотентность (повторный запуск безопасен), блокировки (нет двойного выполнения) и мониторинг «когда агент отработал в последний раз».

Зачем нужны задачи по расписанию

Веб по своей природе синхронный: пришёл запрос — сервер отдал ответ. Но у магазина полно работы, которая не привязана ни к какому конкретному запросу и должна выполняться сама по себе, регулярно. Отправить накопившиеся письма. Забрать из 1С новые цены. Пересчитать рейтинги товаров. Удалить корзины брошенных сессий. Сформировать ночную выгрузку. Всё это — регламентные задачи, и их нельзя «повесить» на действие пользователя, потому что пользователя в нужный момент может просто не быть.

Есть два принципиально разных способа выполнять такую работу:

Ключевая мысль, которую стоит усвоить сразу: агент — это задача, а не процесс. Агент не «крутится в фоне» сам по себе. Он лежит записью в таблице и ждёт, пока кто-то (хит или cron) не проверит: «не пора ли?». Понимание этого снимает половину вопросов о том, почему агенты иногда не срабатывают. Разберёмся детально.

Что такое агенты Битрикса

Агент в 1С-Битрикс — это запись о периодической задаче в системной таблице агентов (b_agent). Каждая запись описывает, что вызывать и когда. Основные атрибуты агента:

ПолеЧто означает
NAMEСтрока вызова — имя функции или метода, который выполняется (например \Vendor\Shop\Cron::syncStocks();)
MODULE_IDМодуль, к которому привязан агент (агенты удаляются вместе с модулем)
ACTIVEАктивность (Y/N) — неактивный агент не запускается
AGENT_INTERVALИнтервал повторения в секундах (3600 — раз в час, 86400 — раз в сутки)
NEXT_EXECДата и время следующего запланированного запуска
LAST_EXECДата и время последнего фактического запуска
IS_PERIODПризнак строгой периодичности (держать запуски по сетке кратно интервалу)
SORTПорядок выполнения относительно других агентов

Функция агента — это обычная PHP-функция или статический метод. Она делает свою работу (шлёт письма, синхронизирует данные) и возвращает строку со своим же вызовом — чтобы ядро знало, как перепланировать её на будущее. Управляют агентами через класс CAgent (AddAgent, RemoveAgent, Update) или через административный раздел «Настройки → Инструменты → Агенты», где виден список всех регламентных задач с их интервалами и временем следующего запуска.

Важно не путать: агенты — это механизм ядра Битрикса, а cron — механизм операционной системы. Это не альтернативы «или-или»: cron может быть способом запускать агенты. Правильная связка на продакшене выглядит так: cron регулярно дёргает Битрикс, а Битрикс внутри выполняет свои агенты и разбор почтовой очереди. Агенты никуда не исчезают — меняется лишь то, кто даёт им «толчок» к выполнению.

Жизненный цикл агента: next_exec и интервал

Чтобы уверенно работать с агентами, нужно понимать их жизненный цикл. Он простой, но в деталях кроется большинство сюрпризов «почему запустилось не тогда».

Когда наступает момент проверки (на хите или по cron), ядро выбирает из таблицы агенты, у которых ACTIVE='Y' и NEXT_EXEC <= текущего времени, и выполняет их по порядку. После выполнения агента ядро вычисляет новое NEXT_EXEC. Вот здесь и работает признак периодичности:

Практический вывод: агент не гарантирует запуск «точно в 3:00». Он гарантирует «не раньше NEXT_EXEC и при первой возможности после». Если вам нужна привязка к конкретному времени суток, надёжнее не агент с суточным интервалом, а отдельный cron-скрипт, который системный планировщик вызовет ровно в назначенный час. Агенты хороши для «примерно каждые N минут/часов», а не для «ровно в момент X».

Жизненный цикл агента Триггер хит или cron даёт «толчок» Проверка NEXT_EXEC ≤ сейчас? и ACTIVE = Y Выполнение функция агента делает работу Перепланирование новое NEXT_EXEC = f(интервал, is_period)
Схема: триггер (хит или cron) запускает проверку, агент с наступившим NEXT_EXEC выполняется, после чего ядро вычисляет новое время запуска по интервалу и признаку периодичности — и цикл повторяется.

Два режима: агенты на хитах и на cron

Один и тот же агент может запускаться двумя способами — и это, пожалуй, главное, что нужно понять про регламентные задачи Битрикса.

Режим «на хитах» (по умолчанию). Битрикс проверяет и выполняет агенты в рамках обычных посетительских запросов. Пришёл человек на сайт — ядро в этом же хите между делом смотрит: не пора ли выполнить какой-нибудь агент? Если пора — выполняет прямо здесь, «на теле» чужого запроса. Настройка «Автоматически проверять активность агентов и рассылку почты на хитах» в модуле main как раз про этот режим.

Режим «на cron». Агенты запускает не посетитель, а системный планировщик операционной системы. В crontab добавлена команда, которая раз в минуту вызывает специальный PHP-скрипт Битрикса; он-то и проверяет/выполняет накопившиеся агенты и разбирает почтовую очередь. Посетительские хиты при этом от агентов освобождаются.

Различие фундаментальное. В первом случае выполнение задач привязано к трафику и выполняется в контексте посетителя. Во втором — идёт по независимому расписанию в отдельном процессе. Отсюда и вытекает вся разница в надёжности, которую разберём дальше.

Агенты на хитах vs агенты на cron На хитах Посетитель Агент в хите тянет за собой нет трафика → нет запуска тяжёлый агент тормозит страницу время неравномерное зависит от посетителей На cron cron ОС Агент в процессе по расписанию запуск в любое время суток не влияет на посетителей стабильный интервал независимо от трафика
Схема: на хитах агенты выполняются в запросах посетителей и зависят от трафика; на cron их по расписанию запускает планировщик ОС в отдельном процессе, независимо от посетителей — отсюда и разница в надёжности.

Почему cron надёжнее хитов

Перевод агентов на cron — стандартная рекомендация для любого боевого проекта на Битриксе. Причин несколько, и все они практические.

Обратная сторона у cron одна: его нужно настроить и следить, что он работает. Если crontab не настроен или сломался, а агенты на хитах вы уже отключили, то регламентные задачи не выполнятся вообще — и это тихая, незаметная авария. Поэтому cron всегда идёт в комплекте с мониторингом «когда в последний раз отработал», о котором поговорим в конце.

Таблица: агент на хите против агента на cron

Компактное сравнение двух режимов, чтобы держать выбор под рукой:

КритерийАгенты на хитахАгенты на cron
Кто даёт «толчок»Запрос посетителяПланировщик ОС (cron)
Зависимость от трафикаПолная: нет хитов — нет запускаНет: работает и без посетителей
Влияние на скорость страницТормозит хит, в котором выполняетсяНе влияет — отдельный процесс
Равномерность интерваловПлавает, зависит от посещенийСтабильная, по расписанию
Ночные и редкие задачиНенадёжноНадёжно
Лимиты выполненияВеб-настройки PHPСвои лимиты CLI-процесса
НастройкаИз коробки, ничего не нужноНужен crontab + отключение хитов
Риск «тихой» аварииЗадачи всё же идут при трафикеСломался cron — не идёт ничего
РекомендацияТолько dev / низкие требованияПродакшен по умолчанию

Вывод из таблицы прямой: для реального магазина cron — стандарт, хиты — временное решение или режим для локальной разработки. Единственная плата за cron — обязательный мониторинг того, что планировщик жив.

Настройка cron: php_interface и cron_events.php

Технически перевод на cron состоит из двух частей: сказать Битриксу «не запускай агенты на хитах, я это делаю через cron» и добавить в системный планировщик регулярный вызов Битрикса. Первую часть настраивают в служебных файлах каталога bitrix/php_interface.

В файле bitrix/php_interface/dbconn.php определяют константу, которая переводит платформу в «режим cron» для агентов и почты. Классический вариант:

<?php
// bitrix/php_interface/dbconn.php

// Переводим агентную подсистему в режим управления по cron:
// агенты и рассылка почты больше не запускаются на хитах посетителей.
define("BX_CRONTAB_SUPPORT", true);

// Флаг того, что текущий запуск — именно cron-контекст,
// проставляется скриптом cron_events.php (см. ниже).
if (!defined("BX_CRONTAB")) {
    define("BX_CRONTAB", false);
}

Параллельно в административном разделе (Настройки → Настройки продукта → Настройки модулей → Главный модуль) отключают опцию «Автоматически проверять активность агентов и рассылку почты на хитах». После этого посетительские запросы перестают тянуть за собой агенты.

Вторая часть — сам вызов по расписанию. В crontab добавляют строку, которая раз в минуту запускает PHP-скрипт разбора событий. Исторически это bitrix/modules/main/tools/cron_events.php; на многих проектах используют собственную обёртку bitrix/php_interface/cron_events.php, которая проставляет флаг BX_CRONTAB и подключает ядро:

# Открыть crontab пользователя веб-сервера: crontab -e
# Запуск разбора агентов и почтовой очереди раз в минуту:
* * * * * /usr/bin/php -f /home/site/www/bitrix/php_interface/cron_events.php >/dev/null 2>&1

Сам скрипт-обёртка в простом виде выглядит так — он поднимает ядро в CLI-режиме и запускает штатный агентный/почтовый обработчик:

<?php
// bitrix/php_interface/cron_events.php
// Помечаем контекст как cron ДО подключения ядра:
$_SERVER["DOCUMENT_ROOT"] = realpath(__DIR__ . "/..");
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS", true);
define("BX_CRONTAB", true);          // ключевой флаг «это cron»
define("CHK_EVENT", true);

require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");

// Разбор агентов и почтовой очереди штатным механизмом ядра
\CAgent::CheckAgents();
define("BX_CRONTAB_SUPPORT", true);
\CEvent::CheckEvents();
На заметку по BitrixVM: если проект работает на официальном окружении BitrixVM (BitrixEnv), значительная часть этой обвязки уже настроена из коробки — окружение само добавляет cron-задачи и управляет агентами. Не дублируйте вызовы вслепую: сверьтесь с тем, что уже настроено на сервере, чтобы агенты не запускались дважды. Точные пути и константы всегда сверяйте с документацией вашей версии платформы — детали менялись между релизами.
cron → cron_events.php → агенты и почта cron ОС * * * * * раз в минуту cron_events.php BX_CRONTAB = true поднимает ядро (CLI) CAgent::CheckAgents() выполняет назревшие агенты CEvent::CheckEvents() разбирает очередь почты
Схема: системный cron каждую минуту вызывает cron_events.php, скрипт поднимает ядро в режиме BX_CRONTAB и через CheckAgents выполняет назревшие агенты, а через CheckEvents разбирает очередь почтовых событий.

Перевод агентов на cron: пошагово

Собираем всё в понятную последовательность. Порядок важен: сначала настраиваем cron и убеждаемся, что он работает, и только потом отключаем хиты — иначе можно на время оставить проект вообще без выполнения регламентных задач.

  1. Проверьте, где и как запускаются агенты сейчас. Загляните в список агентов (админка) и в настройки главного модуля. Зафиксируйте текущий режим — чтобы было к чему откатиться.
  2. Подготовьте cron-скрипт. Создайте (или используйте штатный) cron_events.php, который поднимает ядро с флагом BX_CRONTAB и вызывает разбор агентов и почты. Проверьте путь к PHP-CLI на сервере.
  3. Добавьте задание в crontab. Пропишите запуск скрипта раз в минуту от имени пользователя веб-сервера. Убедитесь, что у процесса есть права на файлы проекта.
  4. Убедитесь, что cron реально работает. Дождитесь пары минут и проверьте, что NEXT_EXEC/LAST_EXEC у агентов начали сдвигаться, а тестовое письмо из очереди ушло. Загляните в лог cron.
  5. Только теперь отключите агенты на хитах. В php_interface и настройках модуля выключите запуск агентов и почты на хитах. С этого момента вся ответственность на cron.
  6. Настройте мониторинг «cron жив». Добавьте проверку, что регламентные задачи выполнялись недавно (например, свежесть LAST_EXEC ключевого агента или внешний heartbeat). Сломавшийся cron не должен оставаться незамеченным.
  7. Проверьте тяжёлые задачи под новыми лимитами. В CLI лимиты времени и памяти отличаются от веб. Убедитесь, что обмен с 1С и рассылки укладываются, при необходимости порционируйте.

Ключевая установка — не отключать хиты вслепую. Сначала докажите себе, что cron выполняет агенты, и только потом снимайте страховку в виде запуска на хитах. Иначе рискуете сутки не замечать, что рассылка и обмен встали.

Создание агента: CAgent::AddAgent

Свои агенты добавляют программно — обычно при установке модуля или разово из служебного скрипта. Базовый метод — CAgent::AddAgent(). Он принимает строку вызова, модуль, признак периодичности, интервал, дату первой проверки, активность, дату первого запуска и сортировку.

<?php
// Регистрируем агент, который раз в час синхронизирует остатки.
// Функция агента должна быть доступна на хите/в cron (например,
// через автозагрузку класса или подключение в init.php).
\CAgent::AddAgent(
    "\\Vendor\\Shop\\StockAgent::run();", // строка вызова (с ; на конце)
    "vendor.shop",                          // MODULE_ID
    "N",                                    // is_period: N — интервал от факта
    3600,                                    // AGENT_INTERVAL, сек (раз в час)
    "",                                     // дата первой проверки (пусто = сейчас)
    "Y",                                    // ACTIVE
    "",                                     // дата первого запуска (пусто = сейчас)
    100                                      // SORT
);

Сама функция агента — это статический метод (или функция), который делает работу и возвращает строку своего вызова, чтобы ядро перепланировало его на следующий раз:

<?php
namespace Vendor\Shop;

class StockAgent
{
    public static function run(): string
    {
        // 1. Основная работа агента (порционно и идемпотентно — см. ниже)
        self::syncStocks();

        // 2. Возвращаем строку СВОЕГО вызова — так ядро знает,
        //    как запланировать следующий запуск через интервал.
        return "\\Vendor\\Shop\\StockAgent::run();";
    }

    private static function syncStocks(): void
    {
        // ... обмен остатками ...
    }
}

Важные детали. Строка вызова должна заканчиваться точкой с запятой и содержать полностью квалифицированное имя (с namespace и экранированными слэшами). Чтобы не плодить дубли при повторной установке, перед добавлением проверяют, нет ли уже такого агента (по строке вызова и модулю), — иначе в списке появятся несколько одинаковых записей, и работа выполнится многократно. Удаляют агент через CAgent::RemoveAgent($name, $module); при удалении модуля его агенты убираются автоматически по MODULE_ID.

Есть и «объектная» надстройка над таблицей агентов в D7 — но под капотом это всё та же подсистема. Как устроено ядро D7 и ORM, через которые удобно писать сервисную логику агента, мы разбираем в статье про D7 и ORM в 1С-Битрикс.

Что возвращает функция агента

Возвращаемое значение функции агента — не формальность, а управляющий сигнал для ядра. Есть три сценария:

Типичная ошибка новичка — не вернуть ничего из функции периодического агента. Тогда ядро трактует результат как пустую строку и удаляет агент после первого же выполнения: задача «отработала один раз и пропала». Если ваш агент должен повторяться, он обязан возвращать строку своего вызова.

<?php
function MyHourlyAgent()
{
    // ... работа ...

    // ОБЯЗАТЕЛЬНО вернуть свой вызов, иначе агент удалится после первого раза
    return "MyHourlyAgent();";
}

function MyOneTimeAgent()
{
    // ... разовая работа ночью ...

    return ""; // пустая строка — агент самоудаляется, задача была разовой
}
Тонкость с ошибками: если функция агента завершится фатальной ошибкой или исключением до return, ядро не получит строку перепланирования корректно, и агент может «застрять» — не сдвинуть NEXT_EXEC и запускаться снова и снова, либо, наоборот, перестать выполняться. Поэтому тело агента оборачивают в try/catch, логируют ошибку и всё равно возвращают строку своего вызова — чтобы сбой одного прогона не ломал расписание.

Идемпотентность агента

Регламентная задача обязана быть идемпотентной — то есть давать корректный результат даже при повторном или наложенном запуске. Это не теоретическая тонкость: агент реально может выполниться дважды (наложение cron и хитов, задержки, ручной перезапуск), и от того, как написана логика, зависит, получите вы дубли писем и двойное списание остатков — или нет.

Главный принцип идемпотентности — работать по состоянию, а не по времени. Плохой агент говорит «обработать всё, что появилось за последний час». Хороший — «обработать всё, что ещё не обработано», помечая каждую запись как обработанную. Тогда повторный запуск ничего не сломает: необработанных записей уже нет.

<?php
public static function run(): string
{
    // Идемпотентно: берём только НЕобработанные записи по флагу,
    // а не «все за интервал». Повторный запуск не создаст дублей.
    $rows = QueueTable::getList([
        'filter' => ['=PROCESSED' => 'N'],
        'order'  => ['ID' => 'ASC'],
        'limit'  => 50, // порция за один проход
    ])->fetchAll();

    foreach ($rows as $row) {
        self::process($row);
        // Помечаем как обработанную СРАЗУ после успешной обработки
        QueueTable::update($row['ID'], ['PROCESSED' => 'Y']);
    }

    return "\\Vendor\\Shop\\QueueAgent::run();";
}

Дополнительные приёмы идемпотентности: использовать во внешних системах ключ идемпотентности (уникальный идентификатор операции, по которому получатель отбрасывает повтор), проверять «уже существует ли результат» перед созданием (нет ли уже документа с таким номером), обновлять записи по первичному ключу, а не вставлять заново. Эти же принципы лежат в основе надёжных интеграций через очереди — подробно мы разбираем их в материале про API, очереди и надёжность интеграций в 1С-Битрикс.

Блокировки и повторный запуск

Идемпотентность защищает от повреждения данных при повторе, но есть смежная проблема — параллельное выполнение одного и того же агента двумя процессами одновременно. Это реально случается: cron запускается каждую минуту, а тяжёлый агент отрабатывает две минуты — второй запуск стартует, пока первый ещё не закончил. Или случайно активны и хиты, и cron.

Защита — блокировка: агент в начале пытается захватить эксклюзивный «замок» и, если не удаётся, тихо выходит, не делая работу повторно. Самый простой и надёжный способ — файловая блокировка через flock:

<?php
public static function run(): string
{
    $self = "\\Vendor\\Shop\\HeavyAgent::run();";
    $lockFile = sys_get_temp_dir() . '/vendor_shop_heavy.lock';
    $fp = fopen($lockFile, 'c');

    // Пытаемся захватить неблокирующую эксклюзивную блокировку.
    // Не удалось — значит уже выполняется другой процесс, выходим.
    if (!$fp || !flock($fp, LOCK_EX | LOCK_NB)) {
        if ($fp) { fclose($fp); }
        return $self; // просто перепланируем, работу не дублируем
    }

    try {
        self::doHeavyWork(); // основная работа под замком
    } catch (\Throwable $e) {
        // логируем, но замок всё равно освободим в finally
        \Bitrix\Main\Diag\Debug::writeToFile($e->getMessage(), '', 'heavy_agent.log');
    } finally {
        flock($fp, LOCK_UN);
        fclose($fp);
    }

    return $self;
}

Альтернативы flock: блокировка на уровне СУБД (GET_LOCK в MySQL), «замок» в опции модуля или в отдельной таблице с проверкой TTL (чтобы зависший процесс не заблокировал задачу навсегда). У блокировки через опцию есть риск «мёртвого замка», если процесс упал, не сняв флаг, — поэтому всегда предусматривайте таймаут или снятие замка в finally. flock хорош тем, что ОС сама освобождает блокировку при завершении процесса.

Почтовые события и очередь писем

Отправка писем в Битриксе почти всегда идёт через очередь почтовых событий, а не мгновенно. Когда код инициирует почтовое событие (CEvent::Send), письмо не уходит сразу — оно кладётся в таблицу почтовых событий со статусом «к отправке». Фактическую отправку выполняет системный механизм, который порциями разбирает эту очередь. И этот разбор — тоже регламентная задача, завязанная на агентно-cron-подсистему.

Отсюда практические следствия:

Транзакционные письма (подтверждение заказа, смена статуса, восстановление пароля) через очередь работают отлично: важно, что они уйдут в течение минуты-двух. А вот массовые маркетинговые рассылки на десятки тысяч адресов через штатную очередь гнать не стоит — она не рассчитана на такой объём, забьёт очередь и может испортить репутацию домена. Их выносят в специализированный сервис рассылок с прогревом и обработкой отписок. Как связать магазин с внешними системами по расписанию и через события, мы показываем в статье про события и обработчики в 1С-Битрикс.

Обмен с 1С по расписанию

Обмен с 1С — одна из самых чувствительных к расписанию задач магазина. Товары, цены, остатки, статусы заказов должны приходить регулярно и вовремя. И здесь режим запуска агентов играет решающую роль.

Обмен бывает двух типов по инициатору:

Если обмен, инициируемый сайтом, повесить на агент на хитах, получаем классическую ловушку: ночью нет посетителей — обмен не идёт — утром остатки и цены устарели. Перевод на cron решает проблему: обмен выполняется по часам независимо от трафика. При этом сама задача обмена должна быть идемпотентной и порционной — падение посреди большого каталога не должно приводить к дублям или потере данных. Полный разбор построения обмена с учётом расписания и надёжности — в статье про интеграцию интернет-магазина с 1С.

Практика: тяжёлый обмен большого каталога — плохой кандидат на «один агент, который делает всё за раз». Такой прогон легко упирается в лимит времени выполнения и обрывается на середине. Правильнее — порционная обработка с сохранением позиции (обработали N товаров, запомнили, где остановились, следующий запуск продолжил) или вынос обмена в отдельный управляемый процесс/очередь, о чём — следующий раздел.

Тяжёлые задачи: не в агенте на хите

Здесь кроется самая частая архитектурная ошибка. Разработчик пишет агент, который делает много работы — генерирует тысячи документов, обходит весь каталог, формирует большую выгрузку — и оставляет его на хитах. Дальше происходит одно из двух: либо агент выполняется в запросе посетителя и тот несколько секунд ждёт пустую страницу, либо агент упирается в лимит времени выполнения PHP (max_execution_time) и обрывается на середине, оставляя работу недоделанной, а данные — в противоречивом состоянии.

Тяжёлые фоновые задачи требуют другого подхода. Есть три уровня решения, от простого к правильному:

Разница между «агент делает всё сам» и «агент ставит задание в очередь» — это разница между хрупкой и надёжной системой. В первом случае сбой роняет всю задачу; во втором — задание остаётся в очереди и будет повторено. Про то, как строить такие очереди и обеспечивать надёжность обмена, у нас есть отдельный подробный материал — API, очереди и надёжность интеграций.

Тяжёлая задача → в фон через очередь Агент ставит задание быстро, не блокирует Очередь задание 1 задание 2 … Воркер обрабатывает порциями Результат 1С / выгрузка сбой → повтор попытки (задание остаётся в очереди)
Схема: агент быстро кладёт задание в очередь и не блокирует ни посетителя, ни другие агенты; отдельный воркер порциями обрабатывает задания, а при сбое задание остаётся в очереди и повторяется — так тяжёлая работа выполняется надёжно.

Пул задач и параллельность

Когда агентов и фоновых задач становится много, встаёт вопрос порядка и параллельности их выполнения. По умолчанию агенты в Битриксе выполняются последовательно: за один проход CheckAgents() ядро перебирает назревшие агенты по порядку сортировки и выполняет их один за другим в одном процессе. Это важно понимать: тяжёлый агент задерживает те, что стоят после него.

Несколько практических следствий и приёмов:

Главный принцип: не всё, что делается по расписанию, должно жить в одном агентном проходе. Агенты хороши для лёгких регулярных задач. Для тяжёлого и параллельного — отдельные процессы и очереди с воркерами, которые масштабируются независимо.

Типы регламентных задач

Чтобы выбрать правильный механизм под конкретную задачу, полезно держать в голове карту типов. Не всё нужно делать агентом — иногда правильнее отдельный cron-скрипт или очередь.

Тип задачиПримерЧем делать
Лёгкая регулярнаяРазбор очереди писем, мелкие пересчётыАгент (на cron)
Периодическая «примерно каждые N»Обновление курсов, чистка временных файловАгент с интервалом
Строго по времени сутокНочная выгрузка ровно в 3:00Отдельный cron-скрипт
Тяжёлая пакетнаяОбмен большого каталога, генерация тысяч документовПорционный агент или cron-скрипт
Тяжёлая и критичнаяМассовая обработка заказов, интеграция с внешним APIОчередь + воркер
Разовая отложеннаяЕдиничная миграция данных ночьюОдноразовый агент (return "")
Реакция на событиеОтправить письмо при смене статуса заказаОбработчик события (не агент)

Обратите внимание на последнюю строку: не всё делается по расписанию. Если задача — реакция на конкретное действие (создан заказ, изменён статус), это работа для обработчика события, а не для агента, который опрашивает состояние. Агент опрашивает («не появилось ли нового?»), событие реагирует («вот, появилось»). Смешивать эти подходы — частая причина лишней нагрузки и задержек.

Отладка: «агент не запускается»

«Агент не срабатывает» — одна из самых частых жалоб. Проблема почти всегда в одной из нескольких типовых точек, и отладка идёт по чёткому дереву проверок. Пройдите его сверху вниз:

  1. Агент вообще существует и активен? Откройте список агентов в админке. Проверьте, что запись есть, ACTIVE='Y', а строка вызова указывает на существующую функцию/метод.
  2. Какое у него NEXT_EXEC? Если время следующего запуска в будущем — агент просто ещё не должен был выполниться. Если далеко в будущем без причины — возможно, кто-то его перепланировал или он «застрял» после ошибки.
  3. Как запускаются агенты — хиты или cron? Если на хитах, а трафика нет (ночь, dev-сайт) — агент физически не дёргается. Зайдите на сайт и проверьте, сдвинулся ли LAST_EXEC. Если на cron — переходите к следующему пункту.
  4. Cron реально вызывает скрипт? Проверьте crontab, логи cron, права процесса. Запустите cron_events.php вручную из консоли и посмотрите, отработал ли он без ошибок.
  5. Функция агента не падает? Временно залогируйте вход в функцию и ключевые шаги. Проверьте лог ошибок PHP: фатальная ошибка или исключение могут прерывать агент до перепланирования.
  6. Модуль агента установлен? Если MODULE_ID указывает на неустановленный/удалённый модуль или класс недоступен (нет автозагрузки, не подключён в init.php) — вызов не состоится.
  7. Нет ли блокировки-«мертвяка»? Если агент использует блокировку и предыдущий процесс упал, не сняв замок, новые запуски будут выходить сразу. Проверьте lock-файл/флаг.
Отладка: «агент не сработал» Агент активен? (ACTIVE=Y) NEXT_EXEC не в будущем? Режим: хиты или cron? cron вызывается? есть трафик? Функция не падает с ошибкой? нет → включить / проверить строку вызова в будущем → застрял/ перепланирован нет трафика / сломан crontab → настроить cron фатал/исключение / нет модуля → смотреть лог, try/catch да на всех шагах → агент должен работать
Схема отладки: сверху вниз проверяем активность агента, его NEXT_EXEC, режим запуска и работу cron, ошибки в функции — каждый шаг ветвится к конкретной причине, пока не найдётся, где обрывается цепочка запуска.

Мониторинг выполнения

Главная опасность фоновых задач — их незаметность. Когда рассылка встала или обмен не прошёл, посетитель этого не видит: страница отдаётся как обычно. Проблему замечают, когда клиент звонит «где моё письмо» или менеджер видит устаревшие остатки. Поэтому регламентные задачи обязательно мониторят.

Что именно контролировать:

Мониторинг превращает «тихую» аварию в громкую: вместо того чтобы узнать о вставшем обмене от рассерженного клиента, вы получаете сигнал и чините проблему заранее. Как выстроить логирование и наблюдаемость фоновых процессов на Битриксе в целом — тема статьи про логирование, отладку и мониторинг в 1С-Битрикс.

Частые ошибки

Регламентные задачи порождают свой набор типовых граблей. Зная их заранее, вы избежите большинства ночных сюрпризов.

Чек-лист регламентных задач

Короткий список, по которому удобно свериться при настройке фоновых задач и на код-ревью:

Вывод

Агенты в 1С-Битрикс — это встроенный механизм периодических задач: запись в таблице с функцией, интервалом и временем следующего запуска, которую ядро выполняет по «толчку» извне. Ключевой выбор — чем давать этот толчок. Режим на хитах привязывает задачи к трафику и выполняет их в запросах посетителей: ненадёжно ночью и вредно для скорости страниц. Режим на cron запускает агенты по расписанию операционной системы, независимо от посетителей и в отдельном процессе, — это стандарт для любого боевого проекта. Перевод на cron — это отключение хитов в php_interface плюс регулярный вызов cron_events.php из crontab, обязательно с проверкой, что cron жив.

Надёжные фоновые задачи держатся на трёх опорах. Идемпотентность — повторный запуск безопасен, потому что задача работает по состоянию, а не по времени. Блокировки — параллельное выполнение невозможно, дублей нет. Правильная архитектура тяжёлого — большую работу не гонят в агенте на хите, а порционируют или выносят в отдельный процесс и очередь с воркером. Плюс обязательный мониторинг, который превращает «тихую» аварию в громкий алерт. Если нужно настроить всё это под ваш проект — мы делаем это в рамках поддержки и highload-разработки на 1С-Битрикс. Смежные материалы — API, очереди и надёжность интеграций, события и обработчики, интеграция магазина с 1С и вся рубрика «Разработка и архитектура».

Частые вопросы

Что такое агенты в 1С-Битрикс простыми словами?

Агенты — это встроенный в ядро 1С-Битрикс механизм периодических задач: функции или методы классов, которые система вызывает через заданные интервалы времени. С их помощью выполняют регламентные задачи, которые не должны зависеть от действий пользователя: отправку писем из очереди, обмен с 1С, пересчёт данных, очистку временных файлов, обновление курсов валют. Каждый агент описан записью в таблице агентов: имя вызываемой функции, модуль, интервал повторения и время следующего запуска (next_exec). Когда наступает это время, ядро выполняет агент и планирует следующий запуск. Важно понимать: агент — это не отдельный демон и не «вечный процесс», а именно задача, которую платформа периодически дёргает — либо на посетительских хитах, либо по расписанию cron.

Чем агенты на cron надёжнее агентов на хитах?

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

Как перевести агенты 1С-Битрикс на cron?

Нужно сделать две вещи. Во-первых, отключить запуск агентов на хитах: в файле bitrix/php_interface/dbconn.php задают константу define("BX_CRONTAB", true) в контексте cron и, как правило, отключают агенты на хитах через настройку «Автоматически проверять активность агентов» / define("BX_CRONTAB_SUPPORT", true). Во-вторых, добавить в системный crontab вызов планировщика Битрикса — обычно раз в минуту запускается PHP-скрипт bitrix/modules/main/tools/cron_events.php (а на новых версиях — bitrix/php_interface/cron_events.php как обёртка), который и выполняет накопившиеся агенты и события почты. После этого агенты перестают зависеть от посетителей. Точную конфигурацию сверяйте с документацией вашей версии и с настройками хостинга — на BitrixVM часть этого уже настроена из коробки.

Можно ли запускать тяжёлую фоновую задачу прямо в агенте?

Нежелательно, особенно если агенты работают на хитах. Тяжёлая задача (массовая выгрузка, генерация тысяч документов, обход большого каталога) в агенте на хите выполняется в рамках посетительского запроса и может упереться в лимит времени выполнения PHP, оборвавшись на середине. Даже на cron один агент выполняется последовательно с другими, и «тяжеловес» блокирует очередь. Правильный подход — разбивать работу на порции (обрабатывать по N записей за запуск, сохраняя позицию) или выносить тяжёлую задачу в отдельный процесс/очередь: агент лишь ставит задание в очередь, а обрабатывает его отдельный воркер. Так задача не мешает ни посетителям, ни другим агентам. Про надёжные очереди и интеграции у нас есть отдельный разбор.

Почему агент не запускается и как это отладить?

Чаще всего причина в одной из нескольких типовых точек. Агент неактивен (ACTIVE=N) или его время следующего запуска next_exec стоит в будущем. На хитах — нет трафика, поэтому агент физически не дёргается; на cron — не настроен или сломан crontab, скрипт cron_events.php не вызывается. Ещё варианты: агент завершается с фатальной ошибкой (тогда next_exec может не сдвигаться и задача «застревает»), модуль агента не установлен, функция агента переименована или удалена, у процесса cron нет прав на запись. Отладка идёт по шагам: проверить запись агента в списке регламентных задач (активность, next_exec), проверить, что cron реально вызывает скрипт (лог), временно залогировать вход в функцию агента, проверить ошибки PHP. В статье приведена диаграмма этой проверки.

Что должна возвращать функция агента и что такое интервал?

Функция агента должна возвращать строку со своим собственным вызовом — например "MyAgentFunction();". Это нужно, чтобы ядро знало, как перепланировать агент на следующий раз (для одноразовых агентов возвращают пустую строку, тогда агент удаляется). Интервал (AGENT_INTERVAL) — это период повторения в секундах: 3600 — раз в час, 86400 — раз в сутки. Есть важный нюанс — признак периодичности (is_period): если он выключен, следующий запуск считается как «время последнего запуска плюс интервал»; если включён, ядро старается держать запуски строго по сетке, кратной интервалу. От этого зависит, «уплывает» ли расписание при задержках. Для точного времени (например, ровно в 3:00) обычно надёжнее отдельный cron-скрипт, а не агент с интервалом в сутки.

Как реализовать очередь писем по расписанию в Битриксе?

Почтовые события в Битриксе не всегда отправляются мгновенно: письмо кладётся в очередь (таблица почтовых событий), а фактическую отправку выполняет системный агент, который порциями разбирает эту очередь. В режиме на хитах этот агент шлёт письма на посетительских запросах — медленно и в зависимости от трафика. Перевод на cron ускоряет и стабилизирует рассылку: скрипт cron_events.php регулярно вызывает разбор очереди, и письма уходят порциями по расписанию, не завися от посетителей и не тормозя их страницы. Для больших рассылок дополнительно ограничивают размер порции за один проход, чтобы не упереться в лимиты SMTP и время выполнения. Массовые маркетинговые рассылки на десятки тысяч адресов лучше выносить в специализированный сервис, а не гнать через штатную очередь событий.

Что делать, чтобы агент не выполнился дважды одновременно?

Нужна идемпотентность и блокировка. Идемпотентность — свойство задачи давать корректный результат даже при повторном запуске: например, помечать обработанные записи и в начале выбирать только необработанные, а не «все за период». Блокировка защищает от параллельного выполнения одного агента двумя процессами (это возможно, если cron запускается чаще, чем агент успевает отработать, или если случайно активны и хиты, и cron). Простейший приём — файловая блокировка через flock на служебном lock-файле или запись «выполняется» в опции модуля с проверкой в начале агента. Если получить блокировку не удалось — агент просто выходит, не делая работу повторно. Так вы избегаете дублей писем, двойного списания остатков и порчи данных при наложении запусков.

Поделиться:

Нужны надёжные фоновые задачи на 1С-Битрикс?

Настроим агенты на cron, переведём обмен и рассылки на стабильное расписание, вынесем тяжёлую работу в очереди и воркеры, поднимем мониторинг «cron жив». Регламентные задачи, которые не встают по ночам.

Игорь Воскресенский

Команда студии B2Bsite. С 2014 года разрабатываем, ускоряем и поддерживаем проекты на 1С-Битрикс: агенты и cron, обмен с 1С по расписанию, очереди и фоновые задачи, кэш, мониторинг и надёжные интеграции для среднего и крупного бизнеса.

← Все статьи блога