При проектировании сложных систем обмена данными между несколькими информационными базами 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С — это полноценный сеанс. Если мы строим цепочку База А -> База Б -> База В, то распределение лицензий будет следующим:
Проанализируем ситуацию, когда лицензий недостаточно. Вложенное соединение просто не установится, и внешнее соединение получит невнятную ошибку. Важно помнить, что если все базы находятся на одном сервере, потребление лицензий может кратно возрасти, что приведет к остановке работы пользователей. Всегда закладывайте запас лицензий при использовании COM-цепочек.
Выясним причину, по которой вложенные соединения часто «отваливаются» без видимых причин. Это связано с разрядностью (32-бит или 64-бит) процессов. Если сервер 1С работает в 64-битном режиме, а компонента comcntr.dll зарегистрирована только в одном варианте или возникают конфликты прав доступа, вызов Новый COMОбъект("V83.COMConnector") внутри серверного процесса может завершиться неудачей.
Для решения этой проблемы часто требуется настройка в консоли Component Services (Службы компонентов) Windows:
comcntr.dll в это приложение.Это позволяет изолировать выполнение COM-объектов от основного процесса rphost, что повышает стабильность вложенных вызовов.
Рассмотрим подробнее проблему утечки ресурсов. COM-соединение потребляет значительный объем оперативной памяти. При вложенности ресурсы суммируются. Если в коде Базы Б произойдет критическая ошибка и объект СоединениеСБазойВ не будет корректно уничтожен (обнулен), сеанс в Базе В может остаться «висеть».
Такие «процессы-зомби» не только занимают память, но и удерживают лицензии. Поэтому в блоке Исключение или в конце выполнения процедуры крайне важно принудительно очищать переменные:
СоединениеСБазойВ = Неопределено;
COMКоннектор = Неопределено;
Несмотря на то, что сборщик мусора 1С должен справляться с этим сам, при вложенных соединениях механизм очистки иногда срабатывает с задержкой или не срабатывает вовсе из-за перекрестных ссылок.
Проанализируем ситуацию, упомянутую в обсуждении: что будет при цикле 1-2-1-2? Если База А вызывает Базу Б, а та снова вызывает Базу А, вы мгновенно получите исчерпание лимита дескрипторов или переполнение стека. Платформа 1С не имеет встроенной защиты от «зацикливания» COM-вызовов.
Чтобы избежать этой ситуации, при проектировании вложенных вызовов мы рекомендуем передавать в параметрах специальный флаг (например, ГлубинаРекурсии). Если флаг указывает на то, что вызов уже является вложенным, следует запретить дальнейшие соединения.
Специалисты сходятся во мнении, что использование цепочек COM-соединений является архитектурно слабым решением по ряду причин:
Вместо того чтобы строить «матрешку» из COM-объектов, разберем более современный подход. Использование HTTP-сервисов позволяет избежать проблем с лицензиями (в некоторых случаях), разрядностью и стабильностью.
Если Базе А нужны данные, которые База Б берет из Базы В, лучше сделать следующее:
HTTPСоединение (это быстро и не создает тяжелый COM-сеанс).Резюме: Использовать COM-соединение внутри другого COM-соединения можно, и это будет работать при правильной настройке прав доступа и COM+ компонентов. Однако из-за высоких рисков нестабильности и сложности поддержки, такие решения стоит применять только в исключительных случаях, когда переход на Web/HTTP сервисы невозможен.