При интеграции баз данных 1С с использованием COM-соединителя (V83.COMConnector) разработчики часто сталкиваются с неожиданным поведением файловых функций. Например, процедура подключается к удаленной базе данных на другом сервере ЛВС, но вызов стандартной функции КаталогВременныхФайлов() возвращает локальный путь на машине, с которой выполняется вызов, а не каталог удаленного сервера. Разберем подробнее механики платформы 1С:Предприятие, вызывающие такое поведение, и выясним, как правильно запустить исполнение кода в контексте целевого сервера.
Проанализируем принцип работы компоненты V83.COMConnector. Библиотека COM-соединителя загружается непосредственно в процесс приложения-инициатора (это может быть тонкий клиент, толстый клиент или процесс rphost сервера-источника). При установке соединения с удаленной базой вызовы методов внешнего объекта выполняются внутри процесса-инициатора, а сеанс внешней базы работает в роли источника данных и исполнителя операций с базой данных.
Согласно документации платформы, функция КаталогВременныхФайлов() возвращает путь к рабочей папке пользователя, от имени которого запущено текущее приложение. Так как вызвающий процесс физически исполняется на локальном компьютере, функция возвращает значение локального профиля операционной системы.
Рассмотрим распространенную ошибку при попытке изменить контекст исполнения с помощью директив компиляции и флагов модулей.
Предположим, в модуле внешней базы с флагами Внешнее соединение и Сервер прописана следующая конструкция:
#Если ВнешнееСоединение Тогда
Процедура СделатьЧтоТоВДругойБазе() Экспорт
ТутДелаемЕщеВызов();
КонецПроцедуры
#КонецЕсли
#Если Сервер Тогда
Процедура ТутДелаемЕщеВызов()
// Ожидается, что этот код выполнится на целевом сервере
ПутьКТемпу = КаталогВременныхФайлов();
КонецПроцедуры
#КонецЕсли
Использование инструкций #Если Сервер или #Если ВнешнееСоединение не переносит исполнение кода на удаленный рабочий процесс кластера (rphost). Эти инструкции являются инструкциями препроцессора и лишь управляют компиляцией кода в зависимости от контекста, в котором исходно загружен модуль. Если инициатор соединения вызвал метод через COM-коннектор, исполнение остается в контексте внешнего соединения на исходной машине.
Посмотрим на практические решения, которые позволяют гарантированно получить контекст кластера удаленного сервера и его локальный каталог временных файлов.
Для того чтобы код гарантированно выполнился в рабочем процессе rphost удаленного сервера, необходимо из COM-соединения сформировать и запустить фоновое задание в подключенной базе.
Рассмотрим пример кода:
// Выполняется через COM-соединение
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(Параметр1);
// Вызываем менеджер фоновых заданий внешней базы
Задание = Соединение.ФоновыеЗадания.Создать("МойСерверныйМодуль.ИсполнитьНаСервере", ПараметрыЗадания);
Задание.Запустить();
Задание.ОжидатьЗавершения();
Внутри процедуры МойСерверныйМодуль.ИсполнитьНаСервере вызов КаталогВременныхФайлов() вернет путь к папке временных файлов службы 1С (например, системной учетной записи usr1cv8) непосредственно на целевом сервере.
Вместо ручной сборки путей через объединение строк с КаталогВременныхФайлов() рекомендуется использовать встроенную функцию ПолучитьИмяВременногоФайла(). При исполнении внутри серверного контекста фонового задания она автоматизирует создание уникального имени файла и корректно учитывает права доступа службы платформы.
Если требуется запустить сам COM-объект на другом физическом сервере, используется второй параметр конструктора Новый COMОбъект:
COMОбъект = Новый COMОбъект("V83.COMConnector", ИмяУдаленногоСервера);
Обратите внимание: данный вариант требует соответствующей настройки прав DCOM (Component Services) на целевой машине в Windows.
Проанализируем важные ограничения при передаче объёмных данных (например, архивов размером 7–9 ГБ) через COM-соединение:
ДвоичныеДанные или Временное хранилище в рамках COM-сеанса приведет к ошибке нехватки памяти (Out of Memory).\\server\share\file.zip), а через COM-соединение передается только строка с путем к файлу.РазделитьФайл() на стороне источника и ОбъединитьФайлы() на стороне приемника для передачи файла небольшими фрагментами.