Предпосылки
Как и в других руководствах по 1С, мы будем использовать компоненту PinkRabbitMQ версии 2.2.0.37.
Введение
RabbitMQ - это средство обмена сообщениями: оно принимает и пересылает сообщения. Вы можете рассматривать его как почтовое отделение: когда вы опускаете письмо, которое хотите отправить, в почтовый ящик, вы можете быть уверены, что почтальон в конечном итоге доставит его вашему получателю. В этой аналогии RabbitMQ - это почтовый ящик, почтовое отделение и почтальон.
Основное различие между RabbitMQ и почтовым отделением заключается в том, что он не работает с бумагой, а принимает, хранит и пересылает двоичные блоки данных R10; сообщения (messages).
RabbitMQ и система обмена сообщениями в целом используют некоторый жаргон.
- Производящий (Producing) означает не что иное, как отправку. Программа, которая отправляет сообщения, является производителем (producer):
- Очередь (queue) - это название почтового ящика в RabbitMQ. Хотя сообщения передаются через RabbitMQ и ваши приложения, они могут храниться только внутри очереди. Очередь ограничена только объемом памяти и диска хоста, по сути, это большой буфер сообщений.
Несколько производителей могут отправлять сообщения, которые попадают в одну очередь, и несколько потребители могут пытаться получить данные из одной очереди.
Вот как мы представляем очередь:
- Потребление (Consuming) имеет то же значение, что и получение. Потребитель (consumer) - это программа, которая в основном ожидает получения сообщений:
Обратите внимание, что производитель (producer), потребитель (consumer) и посредник (broker) не обязательно должны находиться на одном хосте; на самом деле, в большинстве приложений это не так. Приложение также может быть как производителем, так и потребителем.
Приветствую, мир!
В этой части урока мы напишем две небольшие программы: программу-производителя (отправителя), которая отправляет одно сообщение, и программу-потребителя (receiver), которая получает сообщения и распечатывает их. Это "Привет, мир" обмена сообщениями.
На приведенной ниже диаграмме "P" - это наш производитель, а "C" - наш потребитель. Поле посередине представляет собой очередь - буфер сообщений, который RabbitMQ хранит от имени потребителя.
Наш общий дизайн будет выглядеть следующим образом:
Производитель отправляет сообщения в очередь "hello". Пользователь получает сообщения из этой очереди.
Отправка
Наша первая программа отправит в очередь одно сообщение. Первое, что нам нужно сделать, это установить соединение с сервером RabbitMQ.
&НаКлиенте
Процедура Отправка(Команда)
Сервер = "192.168.57.2";
Порт = 5672;
Пользователь = "rmuser";
Пароль = "rmpassword";
ВиртуальныйХост = "/";
КлиентКомпоненты = ПолучитьКомпонентуКлиент();
КлиентКомпоненты.Connect(Сервер, Порт, Пользователь, Пароль, ВиртуальныйХост);
...
Функцию ПолучитьКомпонентуКлиент() можно получить из демонстрационной обработки //infostart.ru/1c/tools/1099423/
Теперь мы подключены к брокеру на компьютере "192.168.57.2". Если бы мы хотели подключиться к брокеру на другом компьютере, мы бы просто указали здесь его имя или IP-адрес.
RabbitMQ - это мультитенантная система: соединения, обмены, очереди, привязки, разрешения пользователей, политики и некоторые другие функции принадлежат виртуальным хостам, логическим группам объектов. Если вы знакомы с виртуальными хостами в Apache или серверными блоками в Nginx, идея аналогична. Более подробно в документации.
Далее, перед отправкой нам нужно убедиться, что очередь получателей существует. Если мы отправим сообщение в несуществующее местоположение, RabbitMQ просто удалит сообщение. Давайте создадим очередь hello, в которую будет доставлено сообщение:
ИмяОчереди = "hello";
Клиент.DeclareQueue(ИмяОчереди, Ложь, Ложь, Ложь, Ложь);
На данный момент мы готовы к отправке сообщения. Наше первое сообщение будет содержать просто строку "Hello World!" и мы хотим отправить его в нашу очередь hello.
В RabbitMQ сообщение никогда не может быть отправлено непосредственно в очередь, оно всегда должно пройти процедуру обмена (exchange). Но давайте не будем углубляться в подробности вы можете прочитать больше об обменах в третьей части этого руководства. Все, что нам нужно знать сейчас, это как использовать обмен данными по умолчанию, обозначаемый пустой строкой. Этот обмен является "особенным" он позволяет нам точно указать, в какую очередь должно быть отправлено сообщение. Имя очереди должно быть указано в параметре routing_key:
ОтправляемоеСообщение = "Hello World!";
routingKey = ИмяОчереди;
Клиент.BasicPublish("", routingKey, ОтправляемоеСообщение, 0, Ложь);
Сообщить("Отправлено 'Hello World!'");
Перед выходом из программы нам нужно убедиться, что сетевые буферы были очищены и наше сообщение действительно было доставлено в RabbitMQ. Мы можем сделать это, аккуратно разорвав соединение.
// В компоненте отключение не предусмотрено, только присутствует правило
// Завершать работу с компонентой посредством обнуления объекта компоненты
Компонента = Неопределено;
Получение
Наша вторая программа будет получать сообщения из очереди и выводить их на экран.
Опять же, сначала нам нужно подключиться к серверу RabbitMQ. Код, отвечающий за подключение к Rabbit, тот же, что и ранее.
Следующим шагом, как и раньше, является проверка существования очереди. Создание очереди с помощью DeclareQueue является идемпотентным R10; мы можем запускать команду столько раз, сколько захотим, и будет создана только одна очередь.
ИмяОчереди = "hello";
КлиентКомпоненты.DeclareQueue(ИмяОчереди, Ложь, Ложь, Ложь, Ложь);
Вы можете спросить, зачем мы снова объявляем очередь R10; мы уже объявляли ее в нашем предыдущем коде. Мы могли бы избежать этого, если бы были уверены, что очередь уже существует. Например, если программа отправки была запущена ранее. Но мы пока не уверены, какую программу запускать первой. В таких случаях рекомендуется повторить объявление очереди в обеих программах.
В источнике на Python: Получать сообщения из очереди сложнее. Это работает путем привязки функции обратного вызова к очереди. Всякий раз, когда мы получаем сообщение, эта функция обратного вызова вызывается библиотекой. В нашем случае "Внешние события не реализованы, т.к. они работают только на клиенте и у нас нет реальных сценариев, когда это может быть полезно"
В нашем случае эта функция выводит на экран содержимое сообщения.
Далее нам нужно сообщить RabbitMQ, что эта функция должна получать сообщения из нашей очереди приветствий:
noConfirm = Истина;
exclusive = Ложь;
Потребитель = Клиент.BasicConsume(ИмяОчереди, "", noConfirm, exclusive, 0);
Для успешного выполнения этой команды мы должны быть уверены, что очередь, на которую мы хотим подписаться, существует. К счастью, мы уверены в этом R10; мы создали очередь выше, используя DeclareQueue.
Параметр noConfirm(auto_ack) будет описан позже.
И, наконец, мы вводим цикл пока есть сообщения, который читает сообщение и выполняет вывод.
Пока Клиент.BasicConsumeMessage("", ОтветноеСообщение, ТегСообщения, 5000) Цикл
Сообщить("Успешно! Из очереди прочитано сообщение " + ОтветноеСообщение);
ОтветноеСообщение = ""; // Обнуляем, чтобы избежать утечку памяти
ТегСообщения = 0; // Обнуляем, чтобы избежать утечку памяти
КонецЦикла;
По окончании цикла закрываем канал для чтения
Клиент.BasicCancel("");
Мы узнали, как отправлять и получать сообщения из именованной очереди. Пришло время перейти к части 2 и создать простую рабочую очередь (work queue).
Благодарю за внимание.
P.S. Думаю будет полезно указать ссылки (пишите в комментариях, приведу в порядок) на
- асинхронное подключение компоненты.
- переиспользование компоненты (много времени уходит на её инициализацию)
- зацикливание с collback на стороне сервера и клиента.
Ссылка на исходник обработки, приведу в порядок при написании всех частей
https://github.com/malikov-pro/1c-rabbit-tutorial
Благодарю за внимание.