RabbitMQ нативно в 1С:
без компонент, прокси и шины
Как заставить 1С напрямую общаться с RabbitMQ, получив outbox/inbox «из коробки» без сторонних библиотек и прокси-сервисов
Эта статья была написана по просьбе одного из наших с вами коллег. Евгений, привет!
Что, если работать с RabbitMQ можно практически нативно средствами самой платформы — и при этом получить уже готовые реализации паттернов outbox и inbox почти безболезненно?
Звучит как что-то невероятное, но способ существует.
Я предполагаю, что у тебя, дорогой читатель, уже есть опыт работы с RabbitMQ или как минимум понимание того, что это такое и какие преимущества он даёт. В этой статье я не буду объяснять, как строить топологию брокера, разбирать виды обменников или способы ответов на сообщения, её цель — показать, что взаимодействовать с RabbitMQ можно нативно, используя только средства самой платформы.
Существующие подходы и их компромиссы
На данный момент мне известно несколько способов прикрутить RabbitMQ к 1С, разной степени боли и жести
| Способ | Проблема |
|---|---|
| Внешние компоненты | Утечки памяти, ограничения концепции фоновых заданий вроде зависаний и необходимости повторной инициализации библиотек |
| Прокси-сервис | В лучшем случае это long polling. Дополнительная точка отказа, на которой тоже нужна буферизация хотя бы с помощью sqlite |
| протоколы MQTT / STOMP | Сложная реализация, часть возможностей AMQP недоступна. STOMP вообще простой текстовый протокол, MQTT ограничен в семантике |
| CDC (Debezium) | Debezium не умеет в RabbitMQ напрямую а Debezium Server требует отдельного инстанса на каждую базу данных |
| 1С:Шина | Требует инфраструктуры, изучения, поддержки но именно её существование делает описанный метод возможным |
Немного теории: как платформа работает с 1С:Шиной
Для работы с 1С:Шиной платформа использует объект метаданных «Сервисы интеграции». Он предоставляет удобный функционал отправки и обработки сообщений, хранит несколько таблиц в базе данных и реализует паттерн Outbox, а также уникальные ключи сообщений для обеспечения идемпотентности.
Внезапно и Сервисы интеграции, и 1С:Шина работают поверх протокола AMQP 1.0 — того же, который поддерживает RabbitMQ. Это и есть наш способ пообщаться.
Как платформа получает список каналов
Чтобы использовать сервис интеграции, сначала нужно создать или загрузить каналы. В форме загрузки указывается адрес 1С:Шины, а дальше платформа делает два последовательных HTTP-запроса:
Платформа отправляет запрос на /auth/oidc/token с заголовком Authorization: Basic <login:password в base64> и ожидает ответ такого вида:
Шаг 2 — Получение списка каналов
Получив токен, платформа запрашивает GET /sys/esb/metadata/channels уже с заголовком Authorization: Bearer <токен>. В ответ она ожидает список каналов:
В нашем же случае — можно отправить что угодно. Имена
process и channel — просто строки, позволяющие связать каналы конфигурации с каналами получаемыми в рантайме.Наша ягодка — поле destination
Когда платформа начинает фактически отправлять сообщение, она делает ещё один запрос для получения токена, и ещё один для получения списка каналов, но уже на GET /sys/esb/runtime/channels. Однако она получает не просто список каналов, а адреса и порт для переключения на AMQP 1.0:
destination — это адрес, по которому платформа будет адресовать сообщения после переключения на AMQP. В случае шины там закодированная base64 + md5 строка с внутренними идентификаторами. Но нас это не смущает, ведь мы можем указать там любой адрес— а именно тот, который понимает RabbitMQ.
А как RabbitMQ маппит адреса AMQP 1.0 на свои собственные?
Ты, дорогой читатель, удивишься, но RabbitMQ при включённом плагине amqp 1.0 имеет специальные форматы адресации которые, вот ведь неожиданность, очень удобно использовать:
Вот и вся магия: подставляем в
destination маршрут в формате RabbitMQ и указываем порт самого брокера (5672). Платформа переключается на AMQP-соединение и общается с кроликом так, будто общается с 1С:Шиной.Практика
Мы поняли, как общаться с RabbitMQ из 1С. Осталось реализовать это на практике.
Вариантов может быть множество — от нормальной реализации с OAuth провайдерами, отдельным сервисом раздачи каналов, настроенной авторизацией на RabbitMQ до раздачи статики вебсервером.
Но я же обещал максимально нативно — поэтому мы реализуем HTTP-сервисы, так ещё и без OAuth (хотя платформа позволяет настроить авторизацию с токеном).
Шаг 1. Поднимаем RabbitMQ
Поднимаем RabbitMQ с плагином management UI. Если версия брокера ниже 4.0 — включаем плагин AMQP 1.0 командой:
Начиная с RabbitMQ 4.0 протокол AMQP 1.0 поддерживается нативно
В панели управления создаём обменник, я назову его 1c_exchange.

_ в именах очередей, обменников и ключей привязки всё же не стоит. В примере он оставлен только ради наглядности.Создаём очередь test и привязываем её к обменнику. Для каждой очереди важно создавать привязки — именно это позволяет отправителю не знать о получателе, а получателю использовать, например, заголовок replyTo.


Вообще, как правило, point-to-point обмен, когда отправитель знает детали адреса получателя (имя базы) — плохая затея. Назначайте роуты по ИНН организаций, скажем, и вычисляйте в процессе работы.
Если все сделано правильно, то список привязок будет выглядеть вот так:

Для получения сообщений создаём отдельную очередь read.queue и также привязываем её к тому же обменнику с маршрутом some.internal.service - другие системы будут писать именно через него:

Шаг 2. HTTP-сервис на стороне 1С
Нам нужен HTTP-сервис с тремя маршрутами:
Решаем проблему авторизации
Здесь есть нюанс: при загрузке каналов платформа сначала авторизуется через Basic (логин и пароль в Base64), а потом переходит на Bearer <токен>. HTTP-сервис 1С без дополнительной настройки для авторизации по токену вернёт ошибку на Bearer-запрос.
Но нас это не пугает — в ответе /auth/oidc/token возвращаем token_type: "Basic" и кладём в id_token ту же Base64-строку логина и пароля, которую получили в заголовке запроса. Тогда все дальнейшие запросы платформа будет подписывать Authorization: Basic <base64> — и сервис их примет, и RabbitMQ в дальнейшем не обидится.
user и password механизма SASL. Если OAuth-плагин RabbitMQ не настроен, брокер ищет пользователя с такими реквизитами — поэтому мы создадим его заранее.Подготовка пользователя:
- 1 Создаем пользователя в 1С, например: логин
Admin, парольtest. - 2 Закодируем строку
Admin:testв Base64 — получитсяQWRtaW46dGVzdA==. - 3 Создаем пользователя в RabbitMQ с именем
QWRtaW46dGVzdA==и паролемQWRtaW46dGVzdA==— они одинаковые.
Код HTTP-сервиса (1С)
Создаём три обработчика — по одному на каждый маршрут:


И добавляем в обработчики следующий код:
Публикуем HTTP-сервис на веб-сервере.
Шаг 3. Настройка обратного прокси (Apache)
Платформа обращается к маршрутам напрямую от адреса сервера, то есть без наших base/hs/etc. Нам нужно перенаправить запросы на эти адреса на наш HTTP-сервис.
Для Apache в файле conf/extra/httpd-vhosts.conf добавляем виртуальный хост с обратным прокси:
В основном httpd.conf раскомментируйте нужные строки:
Если у тебя, читатель, nginx — настройка
proxy_pass значительно проще и займёт где-то пару строк в location.Ну а я могу только позавидовать :)
Шаг 4. Загрузка каналов
Открываем форму загрузки каналов, указываем адрес нашего сервера, логин и пароль пользователя 1С. Нажимаем «Получить каналы» — каналы появятся в дереве метаданных конфигурации.

Для канала чтения добавляем обработчик входящих сообщений:
Обновляем конфигурацию, переходим в управление сервисами интеграции, активируем сервис и указываем логин/пароль пользователя — того же, которого мы создали, именно его base64 строка будет передана в RabbitMQ.

Шаг 5. Отправка сообщения из 1С → RabbitMQ
Итак, мы на финишной прямой, пора попробовать отправить сообщение — создайте обработку, на форме добавьте поле «Сообщение», команду «Отправить» и в обработчик вставьте этот код:
Жмем на заветную кнопку

и...

Соединение установлено! Отлично, а что у нас в очереди some.external.service?

Получилось! В очереди хранится сообщение, в payload - отправленный нами текст, закодированный в формате base64. Осталось только получить сообщение ИЗ очереди.
Шаг 6. Получение сообщения из RabbitMQ → 1С
Переходим в панель RabbitMQ, открываем очередь read.queue и публикуем тестовое сообщение прямо в неё.

Любым способом вызовите метод СервисыИнтеграции.ВыполнитьОбработку(), можно через ту же обработку, и...

Поздравляю! Вы великолепны.
Что в итоге
Мы только что отправили и получили сообщения из RabbitMQ средствами самой платформы 1С. Никаких внешних компонент, никакого прокси-сервиса, никакой шины. Как я и обещал.
Вся настройка сводится к трём вещам:
- 1 Реализовать три HTTP-эндпоинта, которые прикинутся 1С:Шиной
- 2 Подставить в
destinationмаршрут в формате RabbitMQ и нужный порт - 3 Создать в RabbitMQ пользователя с реквизитами в формате Base64
Инструменты для отправки, хранения (Outbox), обработки и идемпотентности предоставляет сама платформа. В реальном проекте имеет смысл добавить провайдер авторизации и вынести конфигурацию каналов в отдельный управляющий сервис, но в целом механика остаётся той же.
Нюансы есть, например, мы не можем использовать другой vhost, а динамическая маршрутизация может вызывать сложности.
Однако для большинства задач, связанных с 1С, хватит и этого, ведь для других клиентов использование AMQP 0.9.1 остается тем же.
Всё же я считаю, что выгоды этого метода превышают любые недостатки, если сравнивать с альтернативами.
@okniceman
Вступайте в нашу телеграмм-группу Инфостарт