Ссылка на предыдущую статью: "7 причин, почему интеграция стала приятной. Не упускайте ряд потрясающих возможностей"
Практические минусы Open Data Protocol
В 1С Предприятие 8.3.5.1068 появилась поддержка автоматического REST-сервиса. Теперь платформа может автоматически формировать REST интерфейс для всего прикладного решения.
Это был глоток свежего воздуха, все данные как на ладони - бери и получай. Конечно, в скором времени появились простые и небольшие сервисы, и работали они стабильно, как часы. Соответственно гений инженерной мысли думает: вот она, "серебряная пуля". Что ж, в порыве эйфории один глобальный проект решено было выполнить, используя: Zato ESB (что же это?) и использовать REST интерфейс OData «1С:Предприятие 8» для обмена между двумя большими системами.
Проблемы, связанные с Open Data Protocol
Для реализации проекта на стороне Zato ESB была нанята команда программистов питонщиков. Основной задачей команды было брать данные из «1С:Предприятие 8» по протоколу OData, а также получать данные при помощи фоновых заданий «1С:Предприятие 8», которые, в свою очередь, передавали изменения данных, необходимых для сторонней системы. На этапе технического задания все выглядело прозрачно, но во время реализации возникли проблемы:
- работа с большими таблицами (некоторые таблицы имели более 100 млн. записей). Получить срез данных было очень проблематично, что часто вызывало падение всех служб 1С;
- получение данных в несколько потоков. Соединения, бывало, часто зависали, и лицензии заканчивались без видимой на то причины, спасал только рестарт службы «1С:Предприятие 8». Забавно было видеть несколько тысяч соединений, которые нельзя удалить;
- танцы с бубнами и велосипедами, чтобы гарантировать доставку сообщений;
- так как обмен работал в две стороны, возникла проблема в контроле логики и верности создания данных в «1С:Предприятие 8»;
- изменение бизнес-процесса в одной системе приводило к необходимости внесения изменений в Zato ESB — в итоге получилась очень большая связность;
- команда питонщиков, по сути, реализовывала буферные копии функционала 1С конфигурации — налицо дублирование кода;
- ребятам питонщикам пришлось учить платформу «1С:Предприятие 8», чтобы понимать, как с этим работать;
- ошибки в самом протоколе OData, что заставляло нас использовать только вышедшие обновления платформы «1С:Предприятие 8» с новой порцией ошибок, уже не связанных с OData.
Проблемы, связанные с Zato ESB
- дорогие программисты, которым пришлось постигать азы платформы 1С;
- ограничиваемся только одним языком программирования для выполнения обменов между системами;
- в промышленных масштабах еще рано использовать, если, конечно, у вас много лишних серверов — можно попробовать на свой страх и риск;
- иногда сервис падал без видимой причины, и докопаться до "почему?" не удалось.
Проект сейчас в режиме "заморожен" и чувствую, что вскоре будет полностью закрыт, в связи с техническими причинами, описанными выше.
7 причин, почему интеграцию необходимо строить на очередях
На данном этапе были переосмыслены все ошибки, было принято решение интеграцию строить на очередях, пока видны только одни плюсы, недостатки незаметны:
- используя очереди RabbitMQ, мы не ограничиваем себя одним языком программирования. Мы можем использовать, в большинстве случаев, родные языки систем, которые интегрируются, для отправки и приема сообщений;
- для гарантии доставки нам не нужно доставать бубны и велосипеды, если сообщение не может быть положено в очередь, то и транзакция будет безболезненно отменена;
- интеграция одной системы к многим и наоборот выполняется одной-единственной настройкой роутинга в RabbitMQ;
- простота формата сообщений, это бинарные данные — мы используем JSON, который переводится в бинарный формат;
- при высокой нагрузке, на довольно слабом виртуальном сервере, в очередь были доставлены все сообщения;
- каждый элемент системы не связан с другими элементами другой системы и бизнес-логика не дублируется, контроль целостности данных проверяется в едином месте в той системе, для которой эти данные предназначены;
- множество типов очередей, даже такие, что позволяют выполнять remote procedure call, но нужно стараться, чтобы системы были минимально связаны, бизнес-логика в «1С:Предприятие 8», а рабочие места, например, это мобильное приложение или веб-сайт.
Передача сообщения из «1С:Предприятие 8» в RabbitMQ
Для реализации этого механизма было принято решение отказаться от веб-сервиса 1С в пользу NativeAPI компоненты, так как планируется передавать большие объемы данных. Весь инструментарий, который понадобится:
- Использование .NET сборок в 1С 8.2, 8.3 без установки и без регистрации в реестре. Это нам позволит загрузить произвольный c# класс, который будет принимать JSON строку и отправлять в очередь;
- Интеграция корпоративных приложений на платформе 1С (как это было). Полезно для общего развития.
Исходный код, компоненты:
using System; using System.Text; using RabbitMQ.Client; namespace _1CV8Publisher { public class V8Publisher { public string UserName { get; set; } public string Password { get; set; } public string HostName { get; set; } public string Exchange { get; set; } public string RoutingKey { get; set; } public string SengMessage(string message) { try { var factory = new ConnectionFactory() { HostName = HostName, UserName = UserName, Password = Password }; using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: Exchange, routingKey: RoutingKey, basicProperties: null, body: body); } } } catch (Exception e) { return e.ToString(); } return "Data successfully delivered!"; } } }
С помощью NuGet console выполняем команду "install-package RabbitMQ.Client". В проекте должны появиться необходимые ссылки на RabbitMQ.Client. Компилируем, и компонента готова. Реализация общего модуля (все компоненты сохранены в конфигурации как бинарные макеты). На первом этапе загружаем внешнюю компоненту, далее возвращаем ее ссылку в метод, который вызвал инициализацию, на втором этапе, если компонента отличается от Неопределено, — вызываем функцию общего модуля ВыполнитьОтправкуВОчередь.
#Область ПрограммныйИнтерфейс Функция ПолучитьОбъектКласса1CV8Publisher() Экспорт ПодключитьВнешнююКомпоненту("ОбщийМакет.NETLoader", "NET", ТипВнешнейКомпоненты.Native); Попытка Компонента = Новый("AddIn.NET.NETLoader"); Исключение ТекстСообщения = НСтр("ru = 'Ошибка при подключении компоненты ""AddIn.NET.NETLoader"": %ТекстСообщения%'"); ТекстСообщения = СтрЗаменить(ТекстСообщения, "%ТекстСообщения%", ОписаниеОшибки()); ЗаписьЖурналаРегистрации("AddIn.NET.NETLoader", УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения, ); Возврат Неопределено; КонецПопытки; КаталогКомпонент = КаталогВременныхФайлов() + Новый УникальныйИдентификатор; СоздатьКаталог(КаталогКомпонент); ПолучитьОбщийМакет("RabbitMQ").Записать(КаталогКомпонент + "\RabbitMQ.Client.dll"); ПолучитьОбщийМакет("V8Publisher").Записать(КаталогКомпонент + "\1CV8Publisher.dll"); Попытка Компонента.CreateObject(КаталогКомпонент, "1CV8Publisher", "_1CV8Publisher.V8Publisher", , Истина); Исключение ТекстОшибки = Компонента.GetLastError(); Если ПустаяСтрока(ТекстОшибки) Тогда ТекстОшибки = ОписаниеОшибки(); КонецЕсли; ТекстСообщения = НСтр("ru = 'Ошибка при вызове метода ""CreateObject"": %ТекстОшибки%'"); ТекстСообщения = СтрЗаменить(ТекстСообщения, "%ТекстОшибки%", ТекстОшибки); ЗаписьЖурналаРегистрации("1CV8Publisher", УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения, ); Возврат Неопределено; КонецПопытки; Компонента.HostName = "hostname"; Компонента.UserName = "admin"; Компонента.Password = "admin"; Возврат Компонента; КонецФункции // ПолучитьОбъектКласса1CV8Publisher() Функция ВыполнитьОтправкуДанныхВОчередь(Компонента, Exchange, RoutingKey, Message) Экспорт Компонента.Exchange = Exchange; Компонента.RoutingKey = RoutingKey; Результат = Компонента.SengMessage(Message); Если Результат <> "Data delivered successfully!" Тогда ВызватьИсключение Результат; КонецЕсли; Возврат Результат; КонецФункции // ВыполнитьОтправкуДанныхВОчередь() #КонецОбласти
Теперь создадим очереди в RabbitMQ (связь систем 1 к 1, для связей 1 к 2 и больше необходимо создать дополнительные очереди, которые будут заполняться с помощью routing):
Создадим exchanges, в которых укажем routing:
ВыполнитьОтправкуДанныхВОчередь(Компонента, "users", "users.event.create", Message);
Соответственно, после выполнения данной строки кода, в очередь users-create-queue упадут данные из параметра Message. Обратите внимание, нигде не указывается, в какую очередь отправляются данные, а указывается exchange и routing key. Для обмена с двумя системами просто нужно добавить новую очередь, которая предназначена для системы №2, и в exchange добавить тот же routing key, но указать очередь №2. Вот так осуществляется подписка на простые события.
Послесловие
Этот подход работает лучше, чем Zato ESB + OData. Время рассудит, станет ли это "серебряной пулей" или простой рабочей лошадкой для специфических задач интеграции.
Если вам помогла статья, благодарность можно выразить денежно.
Статья в личном блоге клац.