Большинство подобных статей в сообществе 1С почему‑то начинаются с тезисов о том, что «интеграции в 1С — это боль и страдание». Дальше обычно идет длинная статья о том, как «делать интеграции без боли».

Мы с этим подходом категорически не согласны. Интеграции в 1С — это не боль, интеграции в 1С — это нормально. Иногда даже интересно.

И как ни крути, любой разработчик грейдом выше джуна так или иначе с ними сталкивается. А уж разработчика, который дорос до ТА, чем‑то удивить в части интеграций в принципе сложно — все всё уже видели.

В каждой команде обычно есть свои наработки, подходы и проверенные временем куски кода. Мы тоже были такой командой. У нас были свои модули, подсистемы, которые через «сравнение‑объединение» перекочевывали из проекта в проект, и на каждом проекте «допиливались» под конкретные требования. 

Правда, аналитики постоянно жаловались:

  • то ошибки забыли залогировать

  • то логи вообще потерялись

  • то очистку логов забыли

  • то на вопросы «а где посмотреть что не выгрузилось», «а как зарегистрировать к обмену» почему‑то на каждом проекте каждый раз новые ответы...

В общем, нам просто в какой‑то момент это все надоело, и мы решили разработать готовое решение для настройки и разработки интеграций. Разработали, обкатали на нескольких проектах и поняли, что не стыдно им поделиться. 

Так появился RDV‑MI, он же Модуль Интеграции, он же MI, он же «MIшка». Продукт, который лежит на github и которым можно пользоваться. 

Мы не позиционируем MI как «решение проблемы интеграций». Потому что такой проблемы в мире 1С не существует. Все и без нас знают и умеют работать с интеграциями. Но при этом MI может оказаться полезным тем, кто разделяет наши идеи и архитектурные принципы. Поэтому в данной статье мы не будем рассказывать почему MI «лучше конкурентов» и не будем «делиться бесценным опытом». Мы просто расскажем, какие подходы к архитектуре интеграций считаем правильными, почему придерживаемся именно их и как эти принципы привели к тому, что MI стал таким, какой он есть.

Атомарность и последовательность

Один объект — одно сообщение. Почему мы против пакетов? Если объединять объекты в пакеты, неизбежно возникнет классическая ситуация: выгружаем 1000 документов, один падает — откатывается вся транзакция загрузки. Особенно приятно это все наблюдать в высоконагруженной системе, где накопившиеся недоставленные пакеты накопятся в очередь, которая сможет рассосаться примерно никогда. Кроме того, все, кто сталкивался с поиском и отладкой ошибок в типовых пакетных обменах 1С знают насколько это «удобно». Мы сталкивались — нам хватило.

Технический бонус: мы любим использовать брокеры сообщений, а брокеру гораздо комфортней пропускать 1000 маленьких сообщений, чем одно огромное. 

Последствия атомарности. Раз мы не объединяем объекты выгрузки в пакеты, значит нам необходимо по умолчанию соблюдать последовательность. В каком порядке объекты создавались (редактировались) в источнике — в таком они должны появляться в приемнике. Почему? Потому что мы не хотим, чтобы в приемник прилетел сначала договор, а потом контрагент. Да, мы можем записать «битую» ссылку в поле «Владелец» у договора и ждать когда «доедет» контрагент. При этом, если для контрагентов реализован поиск по ИНН‑КПП и найдётся контрагент с другим GUID, то ссылка так и останется битой навсегда.

Как это реализовано в MI. В MI регистрация изменений идет не в план обмена, а в специальный регистр сведений. Каждая его запись — это один объект, с привязкой к точке обмена и с таймстемпом до миллисекунд для сортировки. Таким образом, одна запись = одно атомарное сообщение = один элемент очереди на обработку. Это дает прозрачность, контроль и предсказуемость на всех этапах.

Понятный и гибкий формат. Стандартный JSON с возможностью адаптации

Мы используем формат JSON. Почему, думаем, объяснять в XXI веке никому не нужно. Как выглядит текст сообщения (упрощенный пример):

{
  "data": [
    {
      "_ИмяОбъекта": "Справочник.Контрагенты",
      "_ТипЗначения": "Справочник.Контрагенты",
      "_GUID": "689c1ccc-d02c-11f0-9a80-ac1f6bd14f0a",
      "Наименование": "_Тестовый контрагент",
      "ИНН": "7725396754",
      "ЮрФизЛицо": {
        "_ТипЗначения": "Перечисление.ЮрФизЛицо",
        "_Значение": "ЮрЛицоНеРезидент"
      }
      // ...
    }
  ],
  "meta": {
    "id": "a1582635-fcbc-4648-a47d-dac6d3c5",
    "baseid": "erp1",
    "timestamp": "2025-12-03T09:42:40",
    "objecttype": "Контрагенты"
  }
}

Сообщение делится на два блока:

  • data - сами данные объекта;

  • meta - служебная информация.

Внутри секции data присутствуют служебные поля, такие как "_ИмяОбъекта" или "_ТипЗначения". Они нужны, чтобы MI на стороне приемника мог и самостоятельно идентифицировать, и подобрать нужные значения на этапе загрузки, без дополнительных действий со стороны разработчика. Начинаются с символа "_", чтобы явно их отделить от значений реквизитов. Да, это может выглядеть эстетически непривлекательно и можно было бы их объединить во вложенные объекты JSON, или снабдить префиксом, но не хотелось на текущем этапе усложнять формат сообщения и себе жизнь. Поэтому пока так, может быть когда-нибудь переделаем.

Поля ниже – значения выгружаемых реквизитов. Для примитивных типов вроде бы все очевидно. Ссылочные типы содержат вложенные объекты с обязательным полем "_ТипЗначения".

Секция meta – служебные данные сообщения. Напрямую на логику работы MI не влияют вообще никак, но полезны если в архитектуру включена система мониторинга. Спойлер – у нас такая есть, она готовая, тоже в открытом доступе, о ней чуть ниже. 

Больше никаких хитростей нет, всего этого достаточно, чтобы база-приемник с MI на другом конце понимала, что к ней прилетело и что с этим делать. 

Как быть, если требуется реализовать другой формат? Например, мы хотим обмениваться данными с сайтом, у которого свои требования к JSON, без вложенных объектов, без типов, плоская структура, ключи полей латиницей.

Для выполнения этой задачи, нужно в источнике в специальной переопределяемой процедуре написать код, приблизительно такого вида:

На выходе в секции data получим плоскую структуру, секцию meta по нашему стандарту. Если хотим еще упростить и совсем избавиться от секций data и meta – можно: решается внесением еще нескольких строчек кода. Потеряется возможность мониторинга, но кто мы такие, чтобы запрещать.

Что может работать само - должно работать само. Минимум прикладного кода

Мы хотим, чтобы вход в разработку интеграций был максимально простым. Все, что может работать само «из коробки» должно работать «само из коробки». Если мы понимаем, что в 90% случаев при выгрузке ссылочного реквизита нам в приемнике понадобится его GUID, это означает, что разработчик прикладной интеграции об этом думать вообще не должен. Разработчик должен указать, какой реквизит он хочет выгрузить, все остальное MI понимает и сам. Дополнительные действия требуются только в оставшиеся 10% случаев. 

Чтобы запустилась выгрузка. необходимо в переопределяемом модуле написать код, примерно такого вида

Нет, это не дежа вю. Это, действительно, код похожий на код, который используется в типовых конфигурациях для написания обменов в формате EnterpriseData. Мы его не украли, мы им вдохновлялись. Нам понравился подход, при котором все правила конвертации существуют в единой абстрактной коллекции значений. Ну и привыкать к подобному коду разработчику, знакомому с EnterpriseData, будет проще.

Если нужно реализовать более сложную логику, предусмотрен набор переопределяемых процедур, вызываемых в ключевых шагах процесса выгрузки и загрузки и дающих возможность внести любые изменения в загружаемые и выгружаемые данные на любом из этапов.

MI содержит демонстрационные модули, в которых написан демонстрационный код выгрузки и загрузки. Чтобы посмотреть пример и почитать документацию, разработчику не нужно уходить из конфигуратора.

Low-code?

Low-code в мире 1С — это миф и маркетинг, который к реальности отношения не имеет. Первый «low‑code инструмент» для интеграций придумала ещё сама 1С во времена 7.7 — это «Конвертация данных 2». Но почему‑то интерактивная настройка сопоставления реквизитов, столкнувшись с реальными типовыми конфигурациями и реальными задачами, помогает мало. Итог всегда один и тот же: всё равно приходится писать сотни строк кода. Только зачем‑то в режиме предприятия и без отладки. Не верите — откройте любые типовые правила обмена между типовыми базами.

Бывают ли задачи, где действительно можно было бы обойтись low‑code? Да, бывают. Крайне редко. Обычно это какой‑нибудь MDM с централизованной НСИ. Но мы работаем с 1C:ERP и 1C:ERP УХ. Покажите нам low‑code инструмент, который позволит без единой строчки кода загружать договоры, версии договоров, контрагентов и партнёров, учёт которых ведётся раздельно, а также документ «Заказ клиента» с учётом типового механизма обеспечения потребностей из 1C:УПП в 1C:ERP УХ — мы искренне порадуемся этому инструменту вместе с вами.

Low‑code инструменты, работа с которыми всё равно заканчивается задачей «разработчик, помоги, у меня тут не работает», — как будто теряют свой изначальный смысл.

И ещё момент. Код конвертации, который находится в конфигурации (или расширении — разницы нет), поставляется и тестируется централизованно, живёт в одном месте, не теряется, нормально версионируется гитом и не превращается в горсть внешних файлов.
«Почему обмен встал? Потому что мы десять текстовых файлов перенесли из теста в прод, а одну внешнюю обработку забыли». Думаю, знакомая всем история. У нас такого уже давно нет — и мы хотим, чтобы так было и у вас.

Транспорт обмена

В 99% случаев нам хватает двух транспортов:

  • RabbitMQ

  • HTTP-сервис

Какой использовать? Логика простая. Если архитектура интеграции предполагает:

  • всего две базы (неважно, односторонний или двусторонний обмен)

  • отсутствие перспектив расширения и масштабирования (часто это просто временный обмен на период миграции)

то можно использовать HTTP-сервис. Во всех остальных случаях мы используем RabbitMQ.

Почему брокер в приоритете? Потому что брокер убирает необходимость маршрутизации на стороне 1С. База-источник ничего не знает про приемники – и это прекрасно. У источника ровно одна задача: выгрузить сообщение в брокер. Получить обратно статус обработки — приятно, но это именно приятный бонус, а не квитирование и не команда «переотправь». Источник свою работу сделал в момент отправки.

Добавление новой базы‑приёмника не требует менять архитектуру. Появился новый потребитель справочника “Контрагенты”?

  • создаём новую очередь в брокере,

  • пишем код загрузки в приёмнике,

  • источник об этом не знает и знать не должен.

Это, кстати, ещё один аргумент в пользу того, почему мы не объединяем разные объекты в одно сообщение. В брокере мелкими атомарными сообщениями гораздо проще управлять, маршрутизировать и подключать к ним новых потребителей.

На текущий момент времени MI поддерживает оба этих транспорта. Kafka – в ближайших планах. Файловый обмен, обмен через почту, через FTP – нам такое неинтересно, но если вам нужно, велкам. Контрибьют приветствуется, добавить новый транспорт в MI несложно. 

Почему не ESB

Мы не хотим подгонять данные под чей-то формат. В модели с шиной приходится сначала приводить выгрузку к формату шины, потом формат шины приводить к формату приемника. Мы этого делать не хотим. Более того, мы даже не хотим подгонять сообщения под приемник на стороне источника. Источник должен выгружать объект как есть, в максимально естественном виде. Все остальное – забота приемника. Да, бывают специфические случаи, когда в сообщение нужно добавить связанные данные, но это именно исключение. В 90% случаев мы просто сериализуем объект в JSON. Источник ничего не знает о приемниках, и мы хотим, чтобы так оно и оставалось

Мы не хотим писать и хранить код вне конфигуратора. В шинах это обычная практика и мы в нее не верим. Почему – уже рассказали выше в разделе low-code.

Нужен новый приемник – не трогай источник. Добавляем новую очередь в брокере, пишем обработчик загрузки в приемнике и все. Источник не трогаем. Шину не трогаем. Архитектуру не меняем. Это быстро, просто и удобно.

Шина – это всегда отдельная техподдержка. Стандартная история: сообщение потерялось, шина повела себя странно, внутренняя логика работы шины от нас закрыта. «Обращайтесь в саппорт шины, специалист вернется с курортов Краснодарского края — посмотрит.» Нам лишний «черный ящик» в цепочке интеграции не нужен. Зачем плодить узлы, которые требуют отдельного мониторинга, обновлений, логирования и человеческих ресурсов?

Нет, мы никого не агитируем «не использовать шины». Если кому‑то удобно — пожалуйста. Просто нам комфортнее, предсказуемее и дешевле работать без них.

Высокая скорость обмена

Мы уже описали наш подход: один объект — одно сообщение, последовательная выгрузка.
Но что делать, если обмен нужно ускорить? Или данных настолько много, что очередь превращается в «будет готово через два часа»? Или проект только запускается, и нужно прогрузить сотни тысяч элементов НСИ, а ждать никто не хочет?

Если посмотреть на цепочку обработки:

собрать данные → сформировать сообщение → доставить → распарсить → записать объект в приемник,

то самое узкое место всегда одно и то же – запись объекта в приемнике.

Да, иногда "сбор данных" может тормозить, но это происходит только если разработчик сам себе "выстрелил в ногу". В 99% случаев данные вытаскиваются одним нормальным запросом, даже если нужно подтянуть какие-то дополнительные реквизиты.

Поэтому ускорять нужно именно этап записи в приемник.

Логичный путь – распараллелить то, что можно распараллелить.
Но любое распараллеливание в 1С - это история про осознанность: блокировки, конкурирующие записи, "битые ссылки", несогласованность данных и так далее. Поэтому MI не пытается автоматически "параллелить все подряд". Мы даем инструменты, а решения принимает разработчик.

В MI встроен механизм “отложенной обработки” – мы обычно называем его просто механизм очередей. Любое событие можно выполнить отложено, и загрузка входящих сообщений тоже работает через него.

Внутри этой подсистемы есть:

  • возможность параллелить обработку в рамках одного типа очереди;

  • возможность заводить разные типы очередей, каждая из которых выполняется параллельно с другими.

Поэтому если хочется ускорить загрузку, нас не волнует строгая последовательность, и мы не боимся блокировок, достаточно включить порционную обработку для очереди «Обработка входящих сообщений».

Если же нужна более тонкая логика — пожалуйста: определяем, какие типы сообщений можно обрабатывать параллельно, и регистрируем их в разные типы очередей. Максимальная гибкость и полный контроль со стороны разработчика.

Запрос "дозагрузки" от приемника - антипаттерн

Регулярно сталкиваемся с предложением “решения проблемы битых ссылок” примерно в такой формулировке:

“Если в приёмнике ссылка не найдена, мы отправляем служебное сообщение в источник, он по GUID выгружает недостающий объект, и все работает”.

Подход рабочий – но только пока интеграция состоит из полутора объектов и одного направления обмена.

Как только в обмен вовлечено 30–40 сущностей, у которых есть взаимные ссылки, плюс многосторонний обмен – вся эта схема превращается в прямой путь к зацикливанию запросов, лавине повторных дозагрузок и вполне реальному шансу положить обмен целиком.

Поддерживать такую архитектуру сложно.
Расследовать инциденты – еще сложнее.
Риски – абсолютно ненужные.

Мы никого не критикуем – каждый делает так, как ему удобно.
Но мы с этим подходом сталкивались достаточно раз, чтобы больше никогда так не делать.

И в MI мы сознательно не закладываем такой механизм: он нестабилен по природе и плохо масштабируется.

Контроль целостности данных

Данная задача возникает всегда. Не было ни одного проекта, на котором после настройки интеграции не пришлось бы явно убеждать себя и заказчика в том, что интеграция выполнена корректно и ничего не потерялось. Мы считаем, что данная задача должна решаться "из коробки" и MI это умеет.

Общий подход к контролю работает следующим образом

  • Для каждого объекта на стороне источника и приемника формируется массив реквизитов, которые участвуют в обмене (с заданными правила конвертации)

  • Формируется хеш данного массива

  • Хеш обменивается между источником и приемником

  • На стороне источника и приемника есть отчет, который сравнивает хеши

На выходе мы имеем информацию

  • Какие объекты отличаются в источнике и приемнике

  • Какие объекты в какую базу выгружены

  • Какие объекты не выгружены никуда (или никуда не доехали)

Да, мы бы хотели иметь более подробную информацию – сравнивать не только хеши, но и иметь возможность явно увидеть, какие реквизиты разошлись. Данная задача запланирована и находится в разработке. Ждите обновлений :-)

Да, кстати, для запуска механизма контроля целостности в «простой» версии достаточно просто взвести флажок в соответствующей константе, все остальное заработает «само». Хеш будет формироваться по значениям всех реквизитов, которые участвуют в правилах конвертации. Для «сложных» правил формирования хешей есть переопределяемые процедуры. Таким образом, наш принцип, который мы описывали ранее — все, что может работать «само» должно работать «само», — полностью поддерживается.

Мониторинг

Мы не любим узнавать о наличии проблем от пользователей. Мы хотим проблемы предотвращать. Для этого мы всегда используем инструмент, который дает ответы на вопросы.

  • Все ли базы "живы"?

  • Что происходит со скоростью обмена?

  • Есть ли недоставленные сообщения?

  • Нет ли переполнения очередей?

и так далее.

Мы разработали специальный продукт MI-monitor, который также выложен в открытый доступ. Он представляет собой Clickhouse + Grafana с преднастроенными таблицами и дашбордами. И все это заточено под формат сообщений MI, а также под чтение данных из RabbitMQ или HTTP. Вот один из дашбордов графаны, который показывает скорость доставки. Остальные можно посмотреть по ссылке ниже.

Как поучаствовать

Ссылки

RDV-MI: https://github.com/rdv-team/mi

RDV-MI Monitor: https://github.com/rdv-team/mi-monitor/

Чат продукта в тг: https://t.me/rdv_mi

Видео "Быстрый запуск"

У нас есть ролик, где показано как подключить MI, как настроить транспорт, как создать первый обмен и загрузить объект. Повторить всё самому можно, примерно, за час.

Документация

Документация нормальная. Не “три абзаца и картинка”, а человеческая. Мы знаем, что для мира 1С такое редкость, но мы справились. 

Итог

RDV-MI – это не попытка "внести свет" на рынок интеграций 1С. Это просто аккуратно собранный набор решений, которые мы десятки раз делали вручную.
Теперь они живут в одном модуле.

Если вам близок такой подход – используйте.
Если хотите посмотреть внимательно – заглядывайте в GitHub.
Если хотите поругать – пишите комментарий, комментарии улучшают ER и CTR статьи, а мы только рады.

Комментарии (0)