Application::addBackgroundJob — что происходит после ответа клиенту
Проблема
Метод \Bitrix\Main\Application::addBackgroundJob() часто используют по памяти: передают callback с use и надеются, что «задача выполнится где-то в фоне». На практике у метода строгая сигнатура и несколько неочевидных побочных эффектов из Application::terminate(), о которых молчит PHPDoc. Разберём реальное поведение по коду ядра main/lib/application.php.
Решение
Сигнатура из ядра (main/lib/application.php):
public function addBackgroundJob(
callable $job,
array $args = [],
$priority = self::JOB_PRIORITY_NORMAL
);
Аргументы задачи — это второй параметр $args, а не замыкание с use. Оба варианта работают (внутри вызов идёт через call_user_func_array), но штатный путь — именно $args:
\Bitrix\Main\Application::getInstance()->addBackgroundJob(
[\Vendor\Module\Application\Service\Notifier::class, 'sendWelcome'],
[$userId, $locale],
\Bitrix\Main\Application::JOB_PRIORITY_NORMAL,
);
Доступные приоритеты: JOB_PRIORITY_NORMAL = 100, JOB_PRIORITY_LOW = 50. Очередь построена на SplPriorityQueue — большее число выполняется раньше.
Что именно происходит после отправки ответа, видно в terminate():
// псевдокод из Application::terminate()
\CMain::RunFinalActionsInternal();
session_write_close(); // 1. Сессия закрыта
$pool = $this->getConnectionPool();
$pool->useMasterOnly(true); // 2. Только мастер БД
$this->runBackgroundJobs(); // 3. Запуск джобов
$pool->useMasterOnly(false);
К моменту запуска джобов HttpResponse::send() уже вызвал fastcgi_finish_request() — клиент получил ответ и закрыл соединение. Отсюда прикладные следствия:
- Писать в
$_SESSIONбесполезно — сессия закрыта. Нужна сессия — используйте отдельное хранилище или перенесите логику вMessenger. - Все SQL-запросы идут в мастер, реплики не используются — держите задачи короткими.
- Исключения внутри джобов ловятся и логируются через
ExceptionHandler::writeToLog(), но последнее исключение после прогона всей очереди пробрасывается наверх. На ответ клиента это не повлияет, но зафиксируется в логах php-fpm и может оборвать воркер. - Задачи могут добавлять новые задачи — внешний
while ($this->backgroundJobs->valid())дренирует очередь до пустоты. Следите за идемпотентностью, чтобы не получить бесконечный цикл. - Нет гарантии доставки: падение процесса (OOM, таймаут) — задача теряется. Для надёжной обработки с ретраями используйте
Messenger.
Итог
addBackgroundJob — это не «очередь», а хвост текущего запроса с уже закрытой сессией и мастер-соединением. Подходит для короткой работы в несколько сотен миллисекунд: метрики, уведомления, отложенные логи. Всё, что требует гарантий, — только через Bitrix\Main\Messenger.
Комментарии (0)
Пожалуйста, войдите в аккаунт, чтобы оставить комментарий
Оставить комментарийПока нет ни одного комментария. Будьте первым!
Похожие советы