Покупатель оформляет заказ, а сайт в этот момент дёргает по HTTP чужой сервис: CRM, службу доставки, склад, платёжный шлюз. Пока все системы отвечают за сотни миллисекунд, всё выглядит гладко. Но стоит внешнему API «прилечь» на минуту или ответить с двухсекундной задержкой — и покупатель видит крутящийся спиннер, заказ подвисает, а иногда данные уходят наполовину: в 1С-Битрикс заказ создан, а в CRM его нет. Синхронная интеграция хрупка ровно настолько, насколько ненадёжно самое слабое звено в цепочке.
В этой статье разбираем, как сделать интеграции 1С-Битрикс надёжными с помощью очередей сообщений — RabbitMQ и Kafka. Покажем, чем они отличаются, что такое гарантия «хотя бы один раз», идемпотентность, ретраи с backoff и dead-letter очередь, и как встроить продюсера и воркер в Битрикс без переписывания сайта. Это выжимка из наших проектов по интеграции 1С-Битрикс с внешними системами — без теории ради теории.
Коротко
- Очередь развязывает системы во времени: Битрикс кладёт сообщение и отпускает покупателя, а доставку берёт на себя брокер с ретраями.
- RabbitMQ — для команд «отправитель — исполнитель», Kafka — для потоков событий и множества независимых потребителей.
- Действует гарантия «хотя бы один раз», поэтому дубли неизбежны — обработчик обязан быть идемпотентным.
- Неудачные сообщения ретраятся с нарастающей задержкой и уходят в dead-letter очередь, а не в бесконечный цикл.
- Чтобы сообщение не потерялось между БД и брокером, используйте паттерн transactional outbox.
Почему синхронные интеграции ломаются
Синхронная интеграция — это когда веб-запрос покупателя напрямую ждёт ответа от внешней системы. Оформление заказа в 1С-Битрикс вызывает API службы доставки, ответ этого API нужен, чтобы показать срок и стоимость, и только потом страница отдаётся пользователю. Пока всё работает, схема кажется простой и очевидной. Проблемы начинаются на границах — там, где встречаются две независимые системы с разной надёжностью и разной скоростью.
Разберём типичные режимы отказа синхронной связки:
- Внешний сервис недоступен. API упал, идёт деплой, кончились лимиты. Покупатель либо видит ошибку оформления, либо ждёт таймаут — в обоих случаях заказ под угрозой срыва.
- Медленный ответ. Сервис жив, но отвечает три-пять секунд. Веб-воркер сайта занят ожиданием, под нагрузкой такие «висящие» запросы съедают пул процессов PHP и роняют весь сайт, а не только интеграцию.
- Частичный сбой. Заказ записан в базу Битрикса, но вызов CRM упал после коммита. Данные разошлись: в магазине заказ есть, в CRM его нет, и никто об этом не узнает, пока не позвонит клиент.
- Всплеск нагрузки. Распродажа, сто заказов в минуту. Внешний API держит десять запросов в секунду и начинает отбивать остальные — синхронная схема не умеет сглаживать пики.
Корень всех этих бед один: синхронный вызов жёстко связывает во времени два процесса, которые не обязаны быть онлайн и быстрыми одновременно. Отправитель не может завершить свою работу, пока получатель не ответил. Очередь сообщений разрывает эту связь — и именно поэтому она превращает хрупкую интеграцию в устойчивую.
Что такое очередь сообщений и как она спасает
Очередь сообщений (message queue) — это посредник между системами. Отправитель (продюсер) не вызывает получателя напрямую, а кладёт сообщение в брокер. Получатель (консьюмер, воркер) читает сообщения из брокера в своём темпе и обрабатывает их. Между ними стоит брокер — RabbitMQ или Kafka, — который хранит сообщения, гарантирует доставку и позволяет обеим сторонам работать независимо.
Что это даёт интеграции на практике:
- Развязка во времени (decoupling). Битрикс кладёт сообщение за миллисекунды и сразу отпускает покупателя. Даже если CRM недоступна прямо сейчас, сообщение подождёт в очереди и доставится, когда сервис вернётся.
- Сглаживание нагрузки (buffering). При всплеске заказов очередь набухает, а воркеры разбирают её с той скоростью, которую держит внешний сервис. Пик превращается в ровный поток, никто не отбивает запросы.
- Надёжность через ретраи. Если обработка упала, сообщение не теряется: брокер отдаст его снова. Логику повторных попыток берёт на себя инфраструктура, а не хрупкий пользовательский код.
- Наблюдаемость. Длина очереди — честная метрика здоровья интеграции. Растёт — значит, потребитель не справляется или внешний сервис тормозит; видно сразу, а не постфактум по жалобам.
Ключевая ментальная модель: очередь превращает вопрос «удалось ли прямо сейчас доставить данные во внешнюю систему?» в вопрос «удалось ли положить сообщение в надёжный брокер?». Второе на порядок проще и стабильнее первого, потому что брокер — это ваша инфраструктура, которую вы контролируете, а внешний API — нет.
RabbitMQ и Kafka: в чём разница и что выбрать
Оба продукта называют «очередями», но устроены они принципиально по-разному, и путать их — частая причина неудачных внедрений. Коротко: RabbitMQ — это брокер сообщений, который доставляет команды и удаляет их после подтверждения; Kafka — это распределённый лог событий, который хранит поток и позволяет читать его многократно.
RabbitMQ. Классический брокер по модели AMQP. Продюсер публикует сообщение в обменник (exchange), тот по правилам маршрутизации (routing key) раскладывает его по очередям, консьюмер забирает и после успешной обработки подтверждает (ack). После подтверждения сообщение исчезает из очереди. Сильные стороны — гибкая маршрутизация, приоритеты, TTL сообщений, встроенный механизм отложенной повторной доставки и dead-letter. Это выбор по умолчанию для задач вида «выполни одну команду один раз»: отправить заказ в CRM, поставить письмо в рассылку, списать остаток.
Apache Kafka. Не столько очередь, сколько долговременный журнал событий, разбитый на партиции. Продюсер дописывает событие в конец лога, а потребители читают его, двигая свой указатель (offset). Сообщение не удаляется после чтения — оно живёт заданное время хранения (retention), и его могут прочитать сколько угодно независимых групп потребителей. Kafka силён там, где на одно событие «заказ оформлен» подписаны сразу аналитика, рекомендательная система, склад и уведомления, и где поток измеряется тысячами событий в секунду.
| Критерий | RabbitMQ | Kafka |
|---|---|---|
| Модель | Брокер сообщений (команды) | Распределённый лог событий |
| Судьба сообщения | Удаляется после ack | Хранится по retention, читается многократно |
| Маршрутизация | Гибкая: exchange, routing key | По топикам и партициям |
| Несколько потребителей одного события | Через отдельные очереди | Естественно, через consumer groups |
| Порядок | В пределах очереди | В пределах партиции |
| Типичная нагрузка | От единиц до тысяч сообщений/с | Десятки и сотни тысяч событий/с |
| Когда выбрать для Битрикса | Обмен заказами, письма, задачи, интеграция с CRM/1С | Событийная шина, аналитика, много подписчиков, большой поток |
Практический вывод для большинства проектов на 1С-Битрикс: начинайте с RabbitMQ. Он проще в эксплуатации, покрывает 90% интеграционных задач магазина и даёт из коробки ретраи и dead-letter. Kafka оправдана, когда у вас действительно поток событий и несколько независимых потребителей — иначе вы платите за сложную инфраструктуру, не используя её сильные стороны.
Гарантии доставки: at-least-once и дубли
Прежде чем писать код, нужно принять фундаментальный факт распределённых систем: надёжной доставки «ровно один раз» без оговорок не бывает. На практике выбирают между тремя гарантиями, и понимание разницы определяет весь дизайн обработчика.
- At-most-once (не более одного раза). Сообщение доставляется максимум один раз, но может потеряться. Подходит для некритичных данных вроде метрик, неприемлемо для заказов и денег.
- At-least-once (хотя бы один раз). Сообщение точно не потеряется, но может прийти повторно. Это рабочий режим для интеграций: лучше обработать дважды, чем потерять заказ. Именно его дают RabbitMQ и Kafka при правильной настройке подтверждений.
- Exactly-once (ровно один раз). Заманчиво, но достигается либо дорогими транзакционными механизмами внутри одной системы, либо, что практичнее, комбинацией at-least-once на транспорте плюс идемпотентность на приёмнике. Именно так «ровно один раз» и делают в реальном мире.
Почему дубли неизбежны в at-least-once? Представьте: воркер обработал сообщение, записал заказ в CRM, но в момент отправки подтверждения брокеру оборвалась сеть. Брокер не получил ack, считает сообщение необработанным и через время отдаёт его снова. Воркер видит то же сообщение второй раз — и если он наивно создаст заказ заново, в CRM появится дубль. Проблема не в «плохом коде», а в самой природе гарантии: подтверждение и эффект нельзя атомарно связать через ненадёжную сеть. Единственное честное решение — сделать обработчик устойчивым к повторам, то есть идемпотентным.
Идемпотентность: как пережить повторы
Идемпотентная операция — та, что при повторном применении с теми же данными даёт тот же результат, что и при первом. Повторная доставка сообщения не должна создавать второй заказ, списывать остаток дважды или отправлять письмо ещё раз. Это не опция, а обязательное свойство любого потребителя очереди.
Три рабочих способа обеспечить идемпотентность:
- Уникальный ключ сообщения плюс журнал обработанных. Каждому сообщению присваивается стабильный идентификатор (например, UUID заказа или хэш события). Перед действием воркер проверяет, нет ли этого ключа в таблице «уже обработано». Есть — просто подтверждает сообщение и выходит; нет — выполняет действие и записывает ключ. Это самый универсальный подход.
- Естественная идемпотентность через upsert. Если внешняя система умеет «создать или обновить по внешнему ключу», повтор безопасен сам по себе: второй upsert того же заказа просто перезапишет запись теми же данными. Многие CRM и API поддерживают идемпотентные ключи (Idempotency-Key) именно для этого.
- Проверка состояния перед действием. Перед списанием остатка воркер проверяет, не был ли этот заказ уже проведён; перед отправкой письма — не стоит ли отметка «отправлено». Действие выполняется, только если состояние это допускает.
Практический совет: генерируйте идемпотентный ключ на стороне продюсера в Битриксе, а не на приёмнике. Ключ должен быть детерминированным — привязанным к бизнес-сущности (номер заказа, ID элемента и тип операции), а не к случайности момента отправки. Тогда даже если продюсер по ошибке опубликует сообщение дважды, оба будут нести один ключ, и приёмник схлопнет их в одно действие.
Ретраи, backoff и dead-letter очередь
Даже идеальный обработчик иногда падает: внешний API вернул 503, кончился токен, база временно недоступна. Правильная реакция — не «залогировать и забыть» и не «крутить в бесконечном цикле», а повторить с умом. Здесь работают три связанных механизма.
- Ретраи. После неудачи сообщение возвращается на повторную обработку. Число попыток ограничено — обычно 3–7, — иначе «ядовитое» сообщение будет мучить систему вечно.
- Экспоненциальный backoff. Между попытками растёт задержка: 5 секунд, потом 30, потом 2 минуты, потом 10. Это даёт внешнему сервису шанс восстановиться и не добивает его шквалом повторов. Полезно добавить джиттер (случайный разброс), чтобы тысячи сообщений не ретраились синхронно.
- Dead-letter очередь (DLQ). Когда попытки исчерпаны, сообщение уходит не в никуда, а в отдельную очередь недоставленных. Там его видно, можно разобрать причину, поправить данные или код и переотправить вручную.
В RabbitMQ это собирается штатно: у очереди задаётся dead-letter exchange, а отложенные повторы делают через сообщения с TTL или плагин отложенной доставки. В Kafka паттерн другой — обычно заводят отдельные топики-ретраи с растущей задержкой (retry-5s, retry-30s, retry-2m) и финальный dead-letter-топик, а потребитель перекладывает сообщение по цепочке при неудаче.
Отдельно стоит различать «повторяемые» и «неповторяемые» ошибки. Таймаут внешнего API — повторяемая ошибка, её надо ретраить. А вот сообщение с битой структурой или ссылкой на несуществующий товар ретраить бессмысленно: сколько ни повторяй, результат тот же. Такие сообщения разумно сразу отправлять в DLQ, не тратя попытки. Хороший обработчик различает эти классы ошибок и реагирует по-разному.
Порядок сообщений и ключи партиционирования
Иногда порядок обработки критичен. Классический пример: по одному заказу пришли два события — «создан» и «отменён». Если воркеры обработают их в обратном порядке, заказ окажется сначала отменён, а потом создан — и повиснет активным, хотя клиент его отменил. Понимание того, где порядок гарантирован, а где нет, спасает от таких багов.
В RabbitMQ порядок сохраняется в пределах одной очереди при одном потребителе. Как только вы масштабируете обработку на несколько параллельных воркеров, читающих одну очередь, строгий порядок теряется — сообщения разбираются конкурентно. В Kafka порядок гарантирован в пределах одной партиции, а распределение по партициям идёт по ключу: все события с одним ключом (например, с номером заказа) попадают в одну партицию и обрабатываются строго по очереди.
Практические стратегии:
- Ключуйте по бизнес-сущности. В Kafka используйте номер заказа или ID клиента как ключ партиционирования — так все события одной сущности идут по порядку, а разные сущности обрабатываются параллельно.
- Делайте события самодостаточными. Кладите в сообщение не «изменилось поле X», а полное актуальное состояние или версию. Тогда обработчик может отбросить устаревшее событие по номеру версии, даже если оно пришло с опозданием.
- Не требуйте порядка там, где он не нужен. Если события независимы (отправка письма и списание бонусов), не городите ради них строгий порядок — это ограничит параллелизм без пользы.
Архитектура интеграции через очередь
Соберём всё в цельную картину. Надёжная интеграция 1С-Битрикс через очередь состоит из нескольких чётко разделённых частей, и у каждой своя зона ответственности.
- Продюсер в Битриксе. Обработчик события ядра, который вместо прямого вызова внешнего API формирует компактное сообщение с идемпотентным ключом и публикует его в брокер. Живёт внутри веб-запроса, но работает миллисекунды.
- Брокер. RabbitMQ или Kafka. Хранит сообщения, маршрутизирует, гарантирует доставку, держит dead-letter. Это отдельный сервис, не часть сайта.
- Воркер (консьюмер). Отдельный процесс вне веб-стека: консольный PHP-скрипт под supervisor или обработчик по расписанию. Читает сообщения, обеспечивает идемпотентность, вызывает внешний API, ретраит и подтверждает.
- Внешняя система. CRM, служба доставки, склад, 1С — конечный получатель эффекта.
- Наблюдаемость. Метрики длины очередей, лага потребителей, размера DLQ и оповещения поверх них.
Такое разделение даёт главное преимущество: тяжёлая и ненадёжная работа (общение с внешним миром) вынесена из веб-запроса покупателя в фоновый процесс, который можно масштабировать, перезапускать и чинить независимо от сайта. Сайт остаётся быстрым, а интеграция — управляемой. Если вам ближе разбор надёжности именно на уровне API, у нас есть смежный материал про очереди и надёжность API-интеграций Битрикса, где эти же принципы разложены со стороны контрактов и таймаутов.
Реализация в 1С-Битрикс: продюсер и воркер
Теперь — как это ложится на 1С-Битрикс без переписывания сайта. Продюсера вешаем на событие ядра. Например, при сохранении заказа модуль продаж вызывает событие, к которому мы подключаем свой обработчик. Внутри — не тяжёлый вызов API, а быстрая публикация сообщения:
// init.php — продюсер на событии сохранения заказа
use Bitrix\Main\EventManager;
EventManager::getInstance()->addEventHandler(
'sale', 'OnSaleOrderSaved',
function (\Bitrix\Main\Event $event) {
/** @var \Bitrix\Sale\Order $order */
$order = $event->getParameter('ENTITY');
$message = [
'event' => 'order.saved',
'key' => 'ORD-' . $order->getId(), // идемпотентный ключ
'orderId' => $order->getId(),
'sum' => (float)$order->getPrice(),
'ts' => time(),
];
// Публикуем в брокер за миллисекунды и отпускаем покупателя
QueuePublisher::publish('orders', $message);
}
);
Публикацию в RabbitMQ удобно инкапсулировать в тонкий класс на базе библиотеки php-amqplib. Подключение к брокеру, объявление обменника и очереди с dead-letter, персистентность сообщений:
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
class QueuePublisher
{
public static function publish(string $queue, array $payload): void
{
$conn = new AMQPStreamConnection('127.0.0.1', 5672, 'app', 'secret');
$ch = $conn->channel();
// durable-очередь + маршрут в dead-letter при отказе
$ch->queue_declare($queue, false, true, false, false, false, [
'x-dead-letter-exchange' => ['S', 'orders.dlx'],
]);
$msg = new AMQPMessage(json_encode($payload, JSON_UNESCAPED_UNICODE), [
'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
'message_id' => $payload['key'],
]);
$ch->basic_publish($msg, '', $queue);
$ch->close();
$conn->close();
}
}
Воркер выносим в отдельный консольный скрипт, который подключает ядро Битрикса и бесконечно читает очередь. Ключевые моменты — ручное подтверждение (ack) только после успешной обработки, проверка идемпотентности и аккуратная обработка ошибок:
// worker.php — запускается под supervisor, не в веб-запросе
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
$conn = new AMQPStreamConnection('127.0.0.1', 5672, 'app', 'secret');
$ch = $conn->channel();
$ch->basic_qos(null, 10, null); // не хватать больше 10 неподтверждённых
$ch->basic_consume('orders', '', false, false, false, false, function ($msg) {
$data = json_decode($msg->body, true);
// 1) идемпотентность: уже обрабатывали этот ключ?
if (OrderSyncLog::isDone($data['key'])) {
$msg->ack();
return;
}
try {
// 2) вызов внешней системы (CRM/1С/доставка)
CrmClient::upsertOrder($data);
OrderSyncLog::markDone($data['key']);
$msg->ack(); // 3) подтверждаем ТОЛЬКО при успехе
} catch (RetryableException $e) {
$msg->nack(false, false); // в dead-letter → потом ретрай
}
});
while ($ch->is_consuming()) {
$ch->wait();
}
Обратите внимание: сайт не знает и не ждёт, доступна ли CRM. Он только публикует сообщение. Вся ненадёжная работа живёт в воркере, который перезапускается supervisor'ом при падении и разбирает очередь в своём темпе. Если у вас пока нет отдельного брокера, тот же паттерн «продюсер — очередь — воркер» можно временно реализовать на таблице в БД плюс агент Битрикса, но с ростом нагрузки честный брокер окупается.
supervisor (или systemd) с автоперезапуском и ограничением на число сообщений/времени жизни процесса. PHP-воркер, живущий часами, накапливает утечки памяти — периодический мягкий рестарт лечит это без простоя очереди.
Как это выглядит со стороны админки и инфраструктуры
С точки зрения эксплуатации у вас появляется несколько сущностей вне привычной админки Битрикса: узел брокера, панель управления очередями и процессы-воркеры. У RabbitMQ есть веб-панель управления, где видно очереди, скорость входа/выхода сообщений и длину dead-letter. Схематично панель мониторинга очереди выглядит так:
В самой админке Битрикса при этом почти ничего не меняется: заказы создаются как обычно, обработчик события работает незаметно. Отладку интеграции удобно вести по логам воркера и панели брокера, а не по журналам веб-сервера. Если интеграция должна ходить в 1С, полезно держать в голове общий контракт обмена — про архитектуру серверного взаимодействия мы подробно писали в материале про REST API 1С-Битрикс.
Транзакционный outbox: не потерять сообщение
Есть коварная брешь, о которую спотыкаются даже опытные команды. Продюсер делает две вещи: пишет заказ в базу Битрикса и публикует сообщение в брокер. Это две разные системы, и между ними нет общей транзакции. Что если заказ в БД записался, а публикация в брокер упала (или наоборот)? Данные разойдутся — ровно та проблема, ради которой мы затевали очередь.
Решение — паттерн transactional outbox. Идея в том, чтобы сделать запись сообщения частью той же транзакции БД, что и запись бизнес-данных:
- Пишем в одной транзакции. В рамках сохранения заказа в ту же базу, той же транзакцией, записываем строку в таблицу-outbox: «нужно отправить такое-то сообщение». Либо оба изменения зафиксировались, либо оба откатились — расхождение невозможно.
- Отдельный релей публикует. Фоновый процесс (агент, cron или воркер) читает неотправленные строки из outbox и публикует их в брокер. После подтверждения помечает строку как отправленную.
- Повторы безопасны. Если релей упал между публикацией и отметкой, при следующем проходе он опубликует сообщение снова — а идемпотентность на приёмнике схлопнет дубль. Круг замкнулся: гарантия «хотя бы один раз» плюс идемпотентность.
Outbox добавляет одну таблицу и один фоновый процесс, но закрывает целый класс скрытых потерь данных. На проектах, где цена потерянного заказа высока, этот паттерн окупается первым же предотвращённым расхождением. Если полноценный брокер пока не нужен, outbox-таблица плюс агент Битрикса — это уже вполне рабочая надёжная схема начального уровня.
Мониторинг очередей и метрики
Асинхронная интеграция без мониторинга — это чёрный ящик, который однажды молча перестанет доставлять заказы. Хорошая новость: очереди по своей природе наблюдаемы, метрики лежат на поверхности. Вот что стоит держать под приборами:
| Метрика | Что показывает | Ориентир / реакция |
|---|---|---|
| Длина очереди | Сколько сообщений ждёт обработки | Стабильно низкая; рост — затор, добавить воркеров |
| Лаг потребителя (Kafka) | Отставание чтения от конца лога | Близко к нулю; растёт — потребитель не успевает |
| Скорость вход/выход | Баланс публикации и обработки | Выход ≥ вход в среднем по времени |
| Размер dead-letter | Число неразобранных сбоев | Алерт при превышении порога, ручной разбор |
| Возраст старейшего сообщения | Как долго ждёт самое старое | Секунды-минуты; часы — сигнал деградации |
| Доля ретраев | Насколько часто падает обработка | Рост — проблема на стороне внешнего API |
Минимально достаточный набор оповещений: «очередь растёт дольше N минут», «в dead-letter больше M сообщений», «воркеры не подтверждают сообщения» и «нет активных потребителей». Эти четыре алерта ловят подавляющее большинство инцидентов на ранней стадии — когда ещё ничего не потеряно и есть время среагировать. Метрики удобно выгружать в общий стек мониторинга рядом с метриками самого сайта, чтобы видеть корреляции: например, что рост очереди совпал с деплоем внешнего сервиса.
Типовые сценарии для магазина на Битриксе
Чтобы принципы не висели в воздухе, вот где очереди дают наибольшую отдачу на реальном интернет-магазине:
- Выгрузка заказов в CRM. Заказ оформлен — сообщение в очередь — воркер создаёт сделку в CRM. CRM легла на минуту? Заказы подождут и доедут, покупатель ничего не заметил.
- Синхронизация остатков и цен с 1С. События изменения товара кладутся в очередь, воркер пакетно применяет их. Всплеск обновлений после обмена сглаживается очередью, а не бьёт по базе разом.
- Интеграция со складом и WMS. Резервы, отгрузки и статусы ходят через очередь с гарантией доставки и идемпотентностью — детально складную часть мы разбираем в материале про интеграцию WMS и склада с Битриксом.
- Отправка уведомлений. Письма, SMS и пуши — классика для очереди: их не нужно слать в веб-запросе, а при сбое провайдера ретраи спасают доставку.
- Веб-хуки и события наружу. Уведомление партнёрских систем о новом заказе через очередь надёжнее прямого вызова: партнёрский эндпоинт может быть медленным или временно недоступным.
Общий признак «кандидата на очередь»: операция обращается к внешней системе, её результат не обязан быть мгновенным для покупателя, а потеря данных недопустима. Как только вы видите такую тройку условий — это место просится за очередь.
Частые ошибки
- Не сделали обработчик идемпотентным — при повторной доставке в CRM появляются задвоенные заказы, а остатки списываются дважды.
- Подтверждают сообщение (ack) до фактической обработки — при падении воркера сообщение теряется навсегда, ретрай не срабатывает.
- Нет dead-letter очереди — «ядовитое» сообщение либо крутится в бесконечном цикле, либо тихо пропадает.
- Ретраят без backoff — шквал мгновенных повторов добивает уже упавший внешний сервис и мешает ему подняться.
- Публикуют сообщение и пишут в БД без outbox — при сбое между двумя операциями данные расходятся ровно так, как очередь должна была предотвратить.
- Кладут в сообщение гигантский payload вместо ссылки на данные — очередь распухает, а при доставке данные уже устарели.
- Запускают воркер прямо в веб-запросе или по хиту сайта вместо отдельного процесса под supervisor — обработка рвётся вместе с запросом.
- Выбрали Kafka под простой обмен с одной CRM — платят за сложную инфраструктуру, не используя её преимуществ.
Чек-лист внедрения
Сведём всё в практический список, по которому удобно принимать готовность интеграции перед запуском:
- Брокер выбран осознанно. RabbitMQ для команд и обмена, Kafka — только при реальном потоке событий и множестве потребителей.
- Продюсер не блокирует покупателя. Обработчик события кладёт компактное сообщение и сразу отпускает веб-запрос, тяжёлая работа вынесена в воркер.
- Идемпотентный ключ есть. Каждое сообщение несёт детерминированный ключ, приёмник проверяет журнал обработанных перед действием.
- Подтверждение только при успехе. Ack выставляется после фактической обработки; при сбое — nack и ретрай.
- Ретраи с backoff и DLQ. Настроены ограниченные попытки с нарастающей задержкой и dead-letter очередь для исчерпавших лимит.
- Outbox против расхождений. Публикация сообщения атомарна с записью бизнес-данных через транзакционный outbox.
- Воркеры под supervisor. Процессы автоперезапускаются, ограничены по памяти и времени жизни, масштабируются по числу.
- Мониторинг и алерты. Настроены метрики длины очереди, лага, размера DLQ и оповещения по порогам.
Вывод
Очереди сообщений превращают хрупкую синхронную интеграцию в устойчивую систему, которая переживает падения внешних сервисов, сглаживает всплески нагрузки и не теряет заказы. Формула проста: развязать системы во времени через RabbitMQ или Kafka, принять гарантию «хотя бы один раз», сделать обработчик идемпотентным, добавить ретраи с backoff и dead-letter, а публикацию защитить транзакционным outbox. Сделайте эти вещи — и интеграция 1С-Битрикс перестанет быть источником ночных инцидентов даже под нагрузкой распродажи.