В последнее время я всё чаще слышу про использование RabbitMQ для интеграций, поэтому решила разобраться с этим инструментом самостоятельно. Как обычно, первым делом пошла искать статьи, но столкнулась с неожиданной проблемой - большинство материалов отлично объясняют архитектуру, рассказывают про базовые термины, но не отвечают на вопрос «а что мне сделать прямо сейчас, чтобы это заработало?».
Поэтому я решила пройти весь путь и развернуть RabbitMQ на своем компьютере, настроить очереди, подключиться из 1С, отправить первое сообщение и прочитать другое. А заодно разобраться, где RabbitMQ действительно нужен, а где обычный REST оказывается намного проще и правильнее.
Почему HTTP больше не решает все задачи?
Когда начинаешь изучать RabbitMQ, первый вопрос а зачем нужен брокер сообщений, если уже есть REST API? На самом деле эти технологии не конкурируют между собой. Они решают совершенно разные задачи. Чтобы понять разницу, сначала нужно разобраться в двух подходах к интеграциям: синхронном и асинхронном взаимодействии.
Синхронно (REST) — когда нужно здесь и сейчас
Почти все наши повседневные 1С-интеграции — синхронные. Мы отправляем HTTP-запрос и блокируем выполнение кода, пока не придет ответ.
- Пример 1: Покупатель на кассе. 1С стучится в систему лояльности, чтобы узнать баланс бонусов и финальную сумму чека. Пока ответа нет — чек пробить нельзя. RabbitMQ тут только добавит тормозов и усложнит жизнь.
- Пример 2: Оформление заказа и онлайн-проверка остатков. Задержка в пару секунд уже бесит пользователя. HTTP здесь абсолютный победитель.
Асинхронно (RabbitMQ) - когда объем имеет значение
А теперь представьте ночную выгрузку. Нам нужно отправить во внешнюю систему 800 000 чеков, 150 000 контрагентов и обновить цены. Если пулять это через HTTP, начнутся проблемы. Принимающая база ушла на обновление? Она отвечает не 100 миллисекунд, а 5 секунд? Отвалилась сеть на середине пакета?
Здесь на сцену выходит брокер. 1С больше не ждет ответа. Мы просто кидаем сообщение: вот данные, положи в очередь, дальше разбирайтесь сами. Если вторая система лежит, то сообщения спокойно копятся в брокере, а когда она оживет, то сама заберет всё накопившееся.
Краткий чек-лист:
- Берем RabbitMQ, если данные можно обработать в фоне с небольшой задержкой, важна гарантия доставки, объемы большие, а принимающая сторона может быть нестабильна.
- Берем HTTP, если пользователю нужен мгновенный ответ прямо сейчас на экране.
А как получить ответ от брокера?
Если 1С отправила документ и нам нужно получить обратно его UID из внешней системы, мы просто заводим вторую очередь (очередь ответов). Внешняя система пишет результат туда, а 1С регламентным заданием читает эту очередь и обновляет данные у себя.
Практика
После того как я разобралась с теорией, я пошла проверять всё на практике.
В этой статье я не буду подробно останавливаться на установке Docker, здесь никаких сложностей не возникло – в интернете много инструкций на эту тему.
Наша задача развернуть RabbitMQ, создать собственный Virtual Host, настроить пользователя, создать очереди и выполнить настоящий обмен сообщениями между 1С и брокером.
Поднимаем RabbitMQ за одну команду
Открываем обычную командную строку и выполняем одну команду:
docker run -d --name my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management
Что делает эта команда:
- -d — запускает контейнер в фоне.
- --name my-rabbit — дает ему понятное имя.
- -p 5672:5672 — открывает порт, по которому 1С и CDP будут обмениваться сообщениями (служебный порт).
- -p 15672:15672 — открывает порт для веб-интерфейса.
- rabbitmq:3-management — скачивает официальный образ версии 3 вместе с веб-панелью управления (это очень важно, чтобы посмотреть глазками).
Как только контейнер запустится (это займет минуту-две), можно открыть браузер и перейти по адресу: http://localhost:15672
- Логин: guest
- Пароль: guest

После входа нас встречает панель управления. Честно скажу, когда я впервые увидела эту панель, мне стало немного не по себе. Вкладок тьма, настроек еще больше. Но выдыхаем: для базовой интеграции нам понадобятся всего три вещи.
Virtual Host (Виртуальный хост)
В RabbitMQ принято изолировать проекты друг от друга. Virtual Host — это как отдельная информационная база в 1С. Там свои пользователи, свои очереди, и они никак не пересекаются с соседями. Идем во вкладку Admin -> Virtual Hosts и создаем. Для нашего примера создадим отдельный Virtual Host.

Пользователь
В реальных проектах конечно никто не использует стандартного пользователя guest, поэтому следующим шагом я настроила нового пользователя

Очереди (Queues)
Теперь можно перейти к самому интересному. Сообщения должны где-то храниться и в RabbitMQ для этого существуют очереди. Для своего теста я решила сделать следующий пример:
Пусть 1С выгружает покупателей в систему лояльности, а обратно получает информацию о чеках. Создадим две очереди - erp.cdp.clients и cdp.erp.receipts. Тип очереди оставляем Classic, включаем Durable, чтобы сообщения не потерялись после перезапуска брокера.

В результате я вижу две очереди:

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

Код в 1С:
Процедура ВыгрузитьПокупателяНаСервере()
// =======================================================
// ШАГ 1: Формируем бизнес-JSON
// =======================================================
JSON = ПолучитьJSONДляСозданияКонтрагента();
// =======================================================
// ШАГ 2: Упаковываем бизнес-JSON в конверт RabbitMQ
// =======================================================
ИмяОчереди = "erp.cdp.clients";
ИмяВиртуальногоХоста = "erp_cdp_test";
// Настройки самого сообщения
СвойстваСообщения = Новый Структура;
СвойстваСообщения.Вставить("delivery_mode", 2); // 2 - сохранять на диск (гарантия от потери при перезагрузке)
ТелоЗапросаRabbit = Новый Структура;
ТелоЗапросаRabbit.Вставить("properties", СвойстваСообщения);
ТелоЗапросаRabbit.Вставить("routing_key", ИмяОчереди);
ТелоЗапросаRabbit.Вставить("payload", JSON); // Кладем наш бизнес-JSON внутрь конверта
ТелоЗапросаRabbit.Вставить("payload_encoding", "string");
ЗаписьJSONRabbit = Новый ЗаписьJSON;
ЗаписьJSONRabbit.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSONRabbit, ТелоЗапросаRabbit);
ТелоДляОтправки = ЗаписьJSONRabbit.Закрыть();
// =======================================================
// ШАГ 3: Отправка HTTP-запроса к API брокера RabbitMQ
// =======================================================
СерверRabbitMQ = "localhost";
ПортHTTP = 15672;
Логин = "1c_user"; // Или guest с правами админа
Пароль = "1c_user";
Соединение = Новый HTTPСоединение(СерверRabbitMQ, ПортHTTP, Логин, Пароль);
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json");
// URL для публикации. Обрати внимание, сюда подставляется наш Virtual Host
URL = "/api/exchanges/" + ИмяВиртуальногоХоста + "/amq.default/publish";
HTTPЗапрос = Новый HTTPЗапрос(URL, Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоДляОтправки);
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
// =======================================================
// ШАГ 4: Обработка ответа
// =======================================================
КодОтвета = Строка(Ответ.КодСостояния);
Если Ответ.КодСостояния = 200 Тогда
JSONОтвет = "Успех! Сообщение положено в очередь. RabbitMQ ответил: " + Ответ.ПолучитьТелоКакСтроку();
Иначе
JSONОтвет = "Ошибка RabbitMQ: " + Ответ.ПолучитьТелоКакСтроку();
КонецЕсли;
КонецПроцедуры
Но при первом запуске вместо успешной отправки я схватила такую ошибку, несмотря на то что код в 1С написан верно:

Отправляемся назад в рэббит и даем права пользователю

После этого в 1С видим успешный успех и танцуем победный танец:

В веб-панели RabbitMQ красиво загорелась единичка - наше сообщение в очереди erp.cdp.clients ждет, когда его заберут. Мы даже можем его просмотреть:


Теперь попробуем получить сообщение обратно
Отправка - это только половина истории. Теперь представим, что внешняя система сформировала чек и кинула его в брокер. Чтобы просимулировать эту ситуацию воспользуемся возможностями самого RabbitMQ - заходим в очередь cdp.erp.receipts, раскрываем блок Publish message, вставляем заранее подготовленный JSON и нажимаем Publish Message.

Теперь в новой очереди появилась единица. Это означает, что сообщение ожидает своего потребителя.

Читаем сообщение из 1С
Теперь всё готово. Остаётся только нажать кнопку Получить чек в нашей обработке.

Внутри у нас выполняется запрос к HTTP API RabbitMQ. Брокер возвращает сообщение. 1С разбирает JSON. После успешного получения RabbitMQ удаляет сообщение из очереди.
Код процедуры получения чека:
Процедура ПолучитьЧекИзRabbitMQНаСервере()
ИмяОчереди = "cdp.erp.receipts";
ИмяВиртуальногоХоста = "erp_cdp_test";
СерверRabbitMQ = "localhost";
ПортHTTP = 15672;
Логин = "1c_user";
Пароль = "1c_user";
// Запрашиваем 1 сообщение из брокера с удалением из очереди (ack_requeue_false)
ТелоЗапросаRabbit = "{""count"":1,""ackmode"":""ack_requeue_false"",""encoding"":""auto""}";
Соединение = Новый HTTPСоединение(СерверRabbitMQ, ПортHTTP, Логин, Пароль);
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json");
URL = "/api/queues/" + ИмяВиртуальногоХоста + "/" + ИмяОчереди + "/get";
HTTPЗапрос = Новый HTTPЗапрос(URL, Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапросаRabbit);
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния = 200 Тогда
СтрокаОтвета = Ответ.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаОтвета);
МассивСообщений = ПрочитатьJSON(ЧтениеJSON);
Если МассивСообщений.Количество() > 0 Тогда
СтрокаPayload = МассивСообщений[0].payload;
ЧтениеБизнесJSON = Новый ЧтениеJSON;
ЧтениеБизнесJSON.УстановитьСтроку(СтрокаPayload);
ДанныеЧека = ПрочитатьJSON(ЧтениеБизнесJSON);
// Формируем красивый многострочный текст для текстового поля
МассивВывода = Новый Массив;
МассивВывода.Добавить("====================================");
МассивВывода.Добавить(" ПОЛУЧЕН НОВЫЙ ЧЕК ИЗ CDP");
МассивВывода.Добавить("Номер: " + ДанныеЧека.receiptNumber + " от " + СтрЗаменить(ДанныеЧека.date, "T", " "));
МассивВывода.Добавить("Покупатель: " + ДанныеЧека.customer.fullName + " (Доступно бонусов: " + ДанныеЧека.customer.bonusBalance + ")");
МассивВывода.Добавить("------------------------------------");
Для Каждого СтрокаТовара Из ДанныеЧека.items Цикл
МассивВывода.Добавить(" • " + СтрокаТовара.name + " | " + СтрокаТовара.quantity + " шт/кг x " + СтрокаТовара.price + " руб. = " + СтрокаТовара.sum + " руб.");
КонецЦикла;
МассивВывода.Добавить("------------------------------------");
МассивВывода.Добавить("Оплата наличными: " + Формат(ДанныеЧека.payment.cash, "ЧДЦ=2") + " руб.");
МассивВывода.Добавить("Оплата картой: " + Формат(ДанныеЧека.payment.card, "ЧДЦ=2") + " руб.");
МассивВывода.Добавить("ИТОГО К ОПЛАТЕ: " + Формат(ДанныеЧека.totalSum, "ЧДЦ=2") + " руб.");
МассивВывода.Добавить("====================================");
ТекстВывода = СтрСоединить(МассивВывода, Символы.ПС);
JSONОтвет1 = ТекстВывода;
КодОтвета1 = "200 (Успешно прочитано)";
Иначе
JSONОтвет1 = "Очередь пуста! Внешняя система пока ничего не прислала.";
КодОтвета1 = "200 (Пусто)";
КонецЕсли;
Иначе
JSONОтвет1 = "Ошибка соединения с RabbitMQ." + Символы.ПС + Ответ.ПолучитьТелоКакСтроку();
КодОтвета1 = Строка(Ответ.КодСостояния);
КонецЕсли;
КонецПроцедуры
Снова открываем RabbitMQ и видим очень приятную картину. В колонке Ready снова стоит ноль. Это означает, что сообщение было успешно получено и удалено из очереди.

Если нажать кнопку ещё раз, обработка честно сообщит, что новых сообщений нет.

Заключение
Подводя итог своему эксперименту, могу сказать одно: не стоит бояться брокеров сообщений.
Да, когда впервые открываешь веб-интерфейс RabbitMQ, от обилия непонятных вкладок и настроек может стать некомфортно. Это, пожалуй, единственный серьезный порог входа. Но как только вы понимаете логику работы (Виртуальный хост -> Пользователь -> Очередь), всё становится интуитивно понятно. Надеюсь, эта статья поможет вам разобраться с этим инструментом.
Проверено на следующих конфигурациях и релизах:
- Управление торговлей, редакция 11, релизы 11.5.27.70
Вступайте в нашу телеграмм-группу Инфостарт