Можно ли использовать COM-соединение внутри другого COM-соединения в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При проектировании сложных систем обмена данными между несколькими информационными базами 1С:Предприятие часто возникает вопрос: можно ли инициировать COM-соединение из сеанса, который сам является COM-соединением? Рассмотрим классический сценарий: База А подключается к Базе Б, а та, в свою очередь, должна программно запросить данные из Базы В через COM-интерфейс. В этой статье мы подробно разберем, насколько жизнеспособна такая архитектура, с какими сложностями вы столкнетесь и какие существуют альтернативы.

Техническая возможность реализации

Сразу ответим на главный вопрос: да, это возможно. Платформа 1С:Предприятие не содержит жестких программных запретов на создание объекта V83.COMConnector внутри кода, который выполняется в контексте другого COM-соединения. На практике разработчики успешно реализовывали цепочки с одним и даже двумя уровнями вложенности. Однако то, что технология позволяет это сделать, не означает, что это будет работать стабильно «из коробки».

Проанализируем типовую ситуацию. Когда вы вызываете экспортный метод в удаленной базе через COM, код выполняется на стороне сервера (или в контексте процесса dllhost.exe). Для этого кода доступно все окружение платформы, включая возможность создавать новые COM-объекты. Рассмотрим пример того, как может выглядеть инициация вложенного соединения:


// Код в Базе Б, который вызывается из Базы А
Функция ПолучитьДанныеИзТретьейБазы() Экспорт
    
    ПараметрыСоединения = "Srvr=""Server_C"";Ref=""Base_C"";Usr=""Admin"";Pwd=""123"";";
    Попытка
        COMКоннектор = Новый COMОбъект("V83.COMConnector");
        СоединениеСБазойВ = COMКоннектор.Connect(ПараметрыСоединения);
        // Выполнение операций в Базе В
        Результат = СоединениеСБазойВ.Справочники.Номенклатура.НайтиПоКоду("001");
        Возврат Результат.Наименование;
    Исключение
        ЗаписьЖурналаРегистрации("COM_Nested", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
        ВызватьИсключение "Ошибка при вложенном COM-соединении: " + ОписаниеОшибки();
    КонецПопытки;
    
КонецФункции

Проблема лицензирования и сеансов

Разберем один из самых критичных моментов — потребление лицензий. Каждое COM-соединение в 1С — это полноценный сеанс. Если мы строим цепочку База А -> База Б -> База В, то распределение лицензий будет следующим:

  1. Для соединения А -> Б требуется одна сеансовая лицензия на сервере Базы Б.
  2. Внутри этого сеанса База Б инициирует соединение с Базой В. Для этого потребуется еще одна лицензия на сервере Базы В.

Проанализируем ситуацию, когда лицензий недостаточно. Вложенное соединение просто не установится, и внешнее соединение получит невнятную ошибку. Важно помнить, что если все базы находятся на одном сервере, потребление лицензий может кратно возрасти, что приведет к остановке работы пользователей. Всегда закладывайте запас лицензий при использовании COM-цепочек.

Разрядность платформы и настройка COM+

Выясним причину, по которой вложенные соединения часто «отваливаются» без видимых причин. Это связано с разрядностью (32-бит или 64-бит) процессов. Если сервер 1С работает в 64-битном режиме, а компонента comcntr.dll зарегистрирована только в одном варианте или возникают конфликты прав доступа, вызов Новый COMОбъект("V83.COMConnector") внутри серверного процесса может завершиться неудачей.

Для решения этой проблемы часто требуется настройка в консоли Component Services (Службы компонентов) Windows:

  1. Создание пустого приложения COM+.
  2. Добавление компоненты comcntr.dll в это приложение.
  3. Установка учетной записи (Identity), от имени которой будет запускаться процесс (обычно это системная учетная запись с правами администратора или пользователь службы 1С).

Это позволяет изолировать выполнение COM-объектов от основного процесса rphost, что повышает стабильность вложенных вызовов.

Управление ресурсами и «процессы-зомби»

Рассмотрим подробнее проблему утечки ресурсов. COM-соединение потребляет значительный объем оперативной памяти. При вложенности ресурсы суммируются. Если в коде Базы Б произойдет критическая ошибка и объект СоединениеСБазойВ не будет корректно уничтожен (обнулен), сеанс в Базе В может остаться «висеть».

Такие «процессы-зомби» не только занимают память, но и удерживают лицензии. Поэтому в блоке Исключение или в конце выполнения процедуры крайне важно принудительно очищать переменные:


СоединениеСБазойВ = Неопределено;
COMКоннектор = Неопределено;

Несмотря на то, что сборщик мусора 1С должен справляться с этим сам, при вложенных соединениях механизм очистки иногда срабатывает с задержкой или не срабатывает вовсе из-за перекрестных ссылок.

Риски рекурсии

Проанализируем ситуацию, упомянутую в обсуждении: что будет при цикле 1-2-1-2? Если База А вызывает Базу Б, а та снова вызывает Базу А, вы мгновенно получите исчерпание лимита дескрипторов или переполнение стека. Платформа 1С не имеет встроенной защиты от «зацикливания» COM-вызовов.

Чтобы избежать этой ситуации, при проектировании вложенных вызовов мы рекомендуем передавать в параметрах специальный флаг (например, ГлубинаРекурсии). Если флаг указывает на то, что вызов уже является вложенным, следует запретить дальнейшие соединения.

Почему вложенный COM — это антипаттерн?

Специалисты сходятся во мнении, что использование цепочек COM-соединений является архитектурно слабым решением по ряду причин:

Рекомендуемая альтернатива: HTTP-сервисы

Вместо того чтобы строить «матрешку» из COM-объектов, разберем более современный подход. Использование HTTP-сервисов позволяет избежать проблем с лицензиями (в некоторых случаях), разрядностью и стабильностью.

Если Базе А нужны данные, которые База Б берет из Базы В, лучше сделать следующее:

  1. База В публикует HTTP-сервис.
  2. База Б обращается к Базе В через HTTPСоединение (это быстро и не создает тяжелый COM-сеанс).
  3. База А получает результат от Базы Б.

Резюме: Использовать COM-соединение внутри другого COM-соединения можно, и это будет работать при правильной настройке прав доступа и COM+ компонентов. Однако из-за высоких рисков нестабильности и сложности поддержки, такие решения стоит применять только в исключительных случаях, когда переход на Web/HTTP сервисы невозможен.

← На главную