В практике интеграции систем на платформе 1С:Предприятие часто возникает вопрос оптимизации ресурсов. Типичный сценарий: есть две базы, и пользователям первой базы необходимо постоянно записывать или считывать данные из второй. Создание отдельного COM-соединения для каждого активного пользователя — процесс ресурсозатратный и медленный, так как инициализация COMConnector может занимать несколько секунд и потреблять значительный объем оперативной памяти. В этой статье мы проанализируем, можно ли «расшарить» одно соединение между всеми пользователями, разберем технические ограничения и найдем архитектурно верные решения.
Для начала выясним причину, по которой нельзя просто создать объект COMObject при входе первого пользователя и поместить его в некое общее хранилище (например, в параметры сеанса или в регистр сведений). Проанализируем природу COM (Component Object Model): это технология, основанная на указателях в адресном пространстве конкретного процесса.
COM-объект — это не набор данных, который можно сериализовать (превратить в байты) и передать по сети или сохранить в базу данных. Это «живой» экземпляр в памяти операционной системы. Когда один пользователь создает соединение, оно живет в контексте его сеанса. Попытка поместить этот объект в ХранилищеЗначений приведет к тому, что при извлечении в другом сеансе вы получите пустую ссылку или ошибку, так как в адресном пространстве второго пользователя по этому адресу ничего не существует.
Таким образом, прямой ответ на вопрос: нет, передать сам объект между сеансами нельзя.
Несмотря на невозможность прямой передачи объекта, мы можем реализовать архитектурную схему, которая позволит всем пользователям использовать преимущества одного постоянно активного соединения. Разберем этот алгоритм по шагам.
Для реализации нам понадобится промежуточное звено. В файловых базах это может быть отдельный запущенный экземпляр 1С («робот»), а в серверных — выделенное фоновое задание.
РегистрСведений (например, «ОчередьЗадачCOM»), который будет служить буфером обмена. В нем должны быть поля: ПараметрыЗапроса (тип ХранилищеЗначений), Статус (Новый, ВРаботе, Выполнено, Ошибка), Результат (тип ХранилищеЗначений).COMConnector и авторизуется в базе-приемнике. Он держит это соединение открытым в глобальной переменной или в модуле.РегистрСведений, упаковывая данные документа (структуру) в ХранилищеЗначений.ОбработчикОжидания) проверяет наличие новых записей в регистре. Найдя задачу, он берет свое «прогретое» соединение, выполняет операцию в базе 2, получает результат и записывает его обратно в регистр, меняя статус на «Выполнено».Рассмотрим пример кода для постановки задачи пользователем:
ДанныеДляПередачи = Новый Структура;
ДанныеДляПередачи.Вставить("Дата", ТекущаяДата());
ДанныеДляПередачи.Вставить("Контрагент", Объект.Контрагент.Наименование);
НоваяЗапись = РегистрыСведений.ОчередьЗадачCOM.СоздатьМенеджерЗаписи();
НоваяЗапись.ID = Строка(Новый УникальныйИдентификатор());
НоваяЗапись.ПараметрыЗапроса = Новый ХранилищеЗначений(ДанныеДляПередачи);
НоваяЗапись.Статус = Перечисления.СтатусыЗадач.Новый;
НоваяЗапись.Записать();
Проанализируем ситуацию с длительным использованием одного COM-соединения. У этого подхода есть существенные технические риски, которые необходимо учитывать при разработке:
1cv8.exe или rphost.exe может разрастись до критических размеров. Рекомендуется реализовать механизм автоматического пересоздания соединения (например, каждые 500 операций или раз в 3 часа).ОбменДанными.Загрузка = Истина и подавляйте любые диалоги.Выясним причину, по которой опытные разработчики советуют отказываться от COM в пользу HTTP-сервисов. COM-соединение требует наличия установленной платформы той же версии на клиентской машине, регистрации библиотек comcntr.dll и прав администратора. Это «хрупкая» технология.
Разберем, как решить задачу автора через HTTP-протокол:
HTTP-сервис. Мы описываем шаблоны URL и методы (POST, GET).HTTPСоединение.Пример обращения к HTTP-сервису вместо COM:
Соединение = Новый HTTPСоединение("server.com", , "admin", "password");
Запрос = Новый HTTPЗапрос("/base2/hs/v1/create_doc");
Запрос.УстановитьТелоИзСтроки(ДанныеВФорматеJSON);
Ответ = Соединение.ВызватьHTTPМетод("POST", Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Обрабатываем успех
КонецЕсли;
Если вы все же решили использовать COM на серверной 64-битной платформе, вы столкнетесь с тем, что 64-битный процесс сервера не может загрузить 32-битный COM-компонент (если версии разнятся). В этом случае проанализируем настройку через Службы компонентов (COM+).
Создание «обертки» в COM+ позволяет вынести COM-соединение в отдельный процесс операционной системы (dllhost.exe). Это дает дополнительный плюс к отказоустойчивости: если COM-соединение критически ошибется и «упадет», основной рабочий процесс сервера 1С останется жив. Это своего рода изоляция, которая позволяет реализовать подобие пула соединений на уровне ОС.
Подведем итог: использовать один и тот же программный объект COMObject в разных сеансах невозможно из-за ограничений архитектуры Windows и 1С. Однако задачу совместного использования ресурсов можно решить через паттерн очереди в информационной базе или (что более правильно) через переход на HTTP/REST интерфейсы. Это избавит вас от проблем с регистрацией библиотек, утечками памяти и сложностями отладки.