Wordpress

Очереди сообщений в веб-разработке: как спасти форму заказа от тайм-аутов и не потерять лиды в CRM

25.05.2026 4 мин чтения
Техническая схема очередей сообщений и интеграции CRM

Каждый, кто настраивал формы отправки заявок или оформление заказа в интернет-магазине, сталкивался с этой проблемой. Пользователь заполняет корзину, вбивает адрес, нажимает «Оформить»… и зависает. Проходит секунда, две, пять, десять. Браузер крутит колесико, а клиент закрывает вкладку и уходит.

Самое обидное: сервер в этот момент делает кучу полезной работы. Генерирует PDF-накладную, отправляет три письма — покупателю, менеджеру, бухгалтеру, стучится по API в курьерскую службу, проверяет остатки на складе, передаёт контакт в CRM Битрикс24. Если курьерский сервис лежит или отвечает медленно — пользователь получает 504 Gateway Timeout. Сделка потеряна, лида нет, данных в CRM тоже.

Я вижу эту картину постоянно на клиентских проектах. Синхронность — главный враг стабильности, когда у формы больше двух внешних интеграций.

Почему синхронный подход не работает

Вот что происходит при синхронной обработке типичной формы заказа:

Пользователь нажимает «Отправить»
  -> PHP-скрипт начинает работу:
     1. Запись в базу сайта          ~50ms
     2. API курьерской службы        ~1500ms
     3. Отправка email (3 письма)    ~2000ms
     4. API CRM Битрикс24            ~800ms
     5. Генерация PDF                ~300ms
     6. Проверка остатков на складе  ~200ms
  -> Общее время ответа: ~5 секунд
  -> Если API доставки лежит: 10-30 секунд, затем 504

Пять секунд — это вечность для формы. По данным Google, 53% мобильных пользователей уходят, если страница грузится дольше трёх секунд. А тут не просто загрузка, а полное зависание: пользователь не понимает, отправилась заявка или нет.

Проблема усугубляется, когда интеграций становится больше. Добавился WhatsApp-бот? Ещё один внешний вызов. Подключили SMS-шлюз? Ещё один. Каждая новая интеграция — точка отказа, которая может положить всю форму.

Как работают асинхронные очереди

Идея простая: разбить процесс на два этапа. Первый — быстрый, пользовательский. Второй — фоновый, серверный.

Быстрый ответ (пользователь):
  1. Записать данные в базу          ~50ms
  2. Положить задачу в очередь       ~5ms
  3. Вернуть «Спасибо, заявка принята»

Фоновый обработчик (воркер):
  1. Отправить данные в CRM
  2. Вызвать API доставки
  3. Отправить email-уведомления
  4. Сгенерировать PDF
  5. Если что-то не удалось — повторить через 30 секунд

Пользователь видит «Спасибо» за 55 миллисекунд. Всё остальное происходит без его участия. Если API CRM лежит — он этого не замечает, потому что задача ушла в очередь и воркер повторит попытку автоматически.

Redis Stream или RabbitMQ — что выбрать

Для большинства проектов на WordPress и Битрикс я рекомендую Redis. Он уже есть на нормальных хостингах, настраивается за полчаса и покрывает 95% сценариев.

RabbitMQ имеет смысл, если очередей много, задачи приоритизированы по-разному и нужен строгий контроль над маршрутизацией сообщений. Для сайта с формой обратной связи это overkill.

Ключевые различия:

  • Redis Stream — проще в настройке, встроен в большинство хостингов, persists on disk. Минус: нет встроенной маршрутизации и сложнее масштабировать на несколько приложений.
  • RabbitMQ — гибкая маршрутизация, подтверждения доставки, удобная панель управления. Минус: отдельный сервис, нужно администрировать.

На shared-хостинге Redis часто уже доступен из коробки. На VDS можно поставить за десять минут: apt install redis-server — и работает.

Пример: отправка лида в Битрикс24 через очередь

Вот упрощённая схема на PHP, которую я использую на клиентских проектах:

// Публикация задачи в Redis Stream
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$redis->xAdd('crm:leads', '*', [
    'name'    => $form_data['name'],
    'phone'   => $form_data['phone'],
    'source'  => 'contact-form',
    'created' => time(),
]);

// Быстрый ответ пользователю
wp_send_json_success('Заявка принята');

// --- Воркер (отдельный процесс, запускается через supervisor) ---

while (true) {
    $messages = $redis->xReadGroup(
        'GROUP', 'crm-workers', 'crm:leads',
        '0', 1, 5000  // ждём до 5 секунд
    );

    foreach ($messages as $msg) {
        $data = $msg['data'];

        // Отправка в CRM
        $result = sendToBitrix24($data);

        if ($result['success']) {
            $redis->xAck('crm:leads', 'crm-workers', [$msg['id']]);
        }
        // Если ошибка — сообщение останется в pending
        // и воркер повторит попытку
    }
}

У каждого сообщения в Redis Stream есть уникальный ID. Это даёт защиту от дублей, о которой я подробно писал в разборе проблем с дублированием сделок в Битрикс24.

Асинхронные очереди Redis в PHP

Что делать, если очередь недоступна

Самый частый вопрос: «А если сам Redis упал? Получается, мы просто теряем заявки?»

Нет. Есть три уровня защиты:

  1. Запись в базу до очереди. Сохраняем данные формы в MySQL/PostgreSQL. Если Redis недоступен — ставим флаг «не отправлено» и cron-задача попробует позже.
  2. Local fallback. Если Redis не отвечает, пишем задачу в локальный файл или таблицу с минимальным overhead. Это медленнее, но надёжнее, чем просто уронить форму.
  3. Health check + алерты. Мониторим доступность Redis и длину очереди задач. Если очередь растёт или воркер не подтверждает обработку — отправляем алерт.

На практике Redis падает редко. Чаще проблемы возникают с внешними API: CRM, доставка, email-сервисы. Именно для них очередь и нужна — чтобы их нестабильность не убивала форму.

Когда очереди не нужны

Не каждую форму нужно усложнять. Если у вас простая форма «Заказать звонок» с единственной интеграцией — отправка письма менеджеру — очередь избыточна. Обычная отправка через wp_mail() с таймаутом в 5 секунд работает нормально.

Очереди оправданы, когда:

  • У формы три и более внешних интеграций (CRM + email + SMS + доставка).
  • Хотя бы один внешний сервис периодически тормозит или недоступен.
  • Стоимость потерянного лида выше, чем час работы разработчика на настройку Redis.

Для интернет-магазина на Битрикс или WooCommerce с интеграцией CRM — очереди практически всегда окупаются. Одна спасённая заявка покрывает все затраты на настройку.

Евгений Слесаренко
Автор

Евгений Слесаренко

Частный разработчик на Bitrix и WordPress. Пишу о том, как делать сайты и сервисы понятнее, сильнее визуально и спокойнее в поддержке.