При интеграции различных конфигураций 1С (например, при обмене данными между «1С:ERP» и «1С:Бухгалтерия») разработчики часто сталкиваются с проблемой производительности. Инициализация каждого нового COM-соединения — это крайне ресурсоемкая операция. Она запускает полноценный рабочий процесс на стороне принимающей базы, выполняет авторизацию пользователя, инициализирует параметры сеанса и загружает модули. Если в базе одновременно работают десятки пользователей, и каждому из них для получения оперативных данных требуется собственное COM-подключение, нагрузка на сервер приложений возрастает лавинообразно.
Естественным желанием разработчика становится попытка создать одно общее подключение, сохранить его в глобальной доступности и использовать во всех сеансах пользователей. Однако попытки реализовать это «в лоб» через механизмы временного хранилища или параметры сеанса неизбежно терпят неудачу. В этой статье мы подробно разберем, почему стандартный подход автора темы не работает, и рассмотрим эффективные архитектурные альтернативы.
Рассмотрим код, который часто пытаются использовать начинающие разработчики:
мСоединениеБП = ПолучитьИзВременногоХранилища(Константы.СтрокаХранилища.Получить());
Если Строка(мСоединениеБП) <> "COMОбъект" Тогда
Константы.СтрокаХранилища.Установить(ПоместитьВоВременноеХранилище(rsОбщийМодульОбмен.ПолучитьПодключениеКСервернойБД(), Новый УникальныйИдентификатор));
мСоединениеБП = ПолучитьИзВременногоХранилища(Константы.СтрокаХранилища.Получить());
КонецЕсли;
Этот алгоритм не будет работать по двум фундаментальным причинам, заложенным в архитектуру платформы 1С:Предприятие:
ПоместитьВоВременноеХранилище, платформа регистрирует переданный объект во временном реестре текущего сеанса и возвращает уникальный адрес (строку вида "e1cib/tempstorage/..."). Если мы запишем эту строку-адрес в константу или общую базу данных, другие пользователи смогут прочитать саму строку. Но при попытке вызвать ПолучитьИзВременногоХранилища в другом сеансе платформа вернет Неопределено, так как у другого сеанса нет физического доступа к памяти первого сеанса.COMОбъект (включая V83.COMConnector) является указателем операционной системы на конкретные области в оперативной памяти и запущенные внешние процессы (например, dllhost.exe или rphost.exe). Такой объект физически невозможно сериализовать. Платформа 1С выдаст ошибку при попытке поместить «живое» COM-соединение во временное хранилище или базу данных.Вывод очевиден: напрямую передать активный COM-объект из одного сеанса пользователя в другой технически невозможно.
---
Прежде чем переписывать всю архитектуру обмена, проанализируем встроенные возможности самой платформы 1С. Мало кто знает, что объект V83.COMConnector умеет самостоятельно управлять повторным использованием физических подключений на уровне операционной системы. Этот механизм называется пулом соединений (Connection Pooling).
Вместо того чтобы изобретать велосипед с передачей объекта, мы можем настроить параметры пула при инициализации коннектора на сервере. Разберем пример реализации:
// Создаем объект внешнего соединения
Коннектор = Новый COMОбъект("V83.COMConnector");
// Настраиваем параметры пула соединений
Коннектор.PoolCapacity = 10; // Максимальное количество удерживаемых открытых соединений в пуле
Коннектор.PoolTimeout = 60; // Время жизни неактивного соединения в пуле в секундах
Коннектор.MaxConnections = 20; // Максимально возможное число одновременно открытых соединений
Как это работает на практике: когда очередной пользователь инициирует подключение методом Коннектор.Connect(СтрокаСоединения), платформа 1С не создает новое сетевое подключение с нуля. Она обращается к пулу операционной системы. Если в пуле есть свободное (ранее созданное другим пользователем) «спящее» соединение с абсолютно такими же параметрами подключения (имя сервера, имя базы, имя пользователя и пароль), то система мгновенно выдает его текущему пользователю. Авторизация и инициализация при этом происходят за доли секунды. Это полностью решает проблему высокой нагрузки на сервер при частых запросах от разных пользователей.
---
Если специфика вашей бизнес-логики не требует мгновенного (интерактивного) ответа «здесь и сейчас», отличным решением станет переход от синхронного COM-взаимодействия к асинхронной очереди задач. Этот паттерн позволяет полностью изолировать пользователей от прямого обращения к внешней базе данных.
Проанализируем схему работы этого паттерна по шагам:
ОчередьЗадачКВнешнейБазе со следующей структурой:
ИдентификаторЗадачи (тип УникальныйИдентификатор).Состояние (тип ПеречислениеСсылка.СостоянияЗадач: ВОчереди, Выполняется, Выполнена, Ошибка), Результат (тип ХранилищеЗначения).ПараметрыЗадачи (тип ХранилищеЗначения), ТекстОшибки (тип Строка).ХранилищеЗначения и записывает новую строку в регистр ОчередьЗадачКВнешнейБазе со статусом ВОчереди.ВОчереди.Результат, меняя статус задачи на Выполнена (или Ошибка).Выполнена, он считывает готовый результат из ресурса Результат.Рассмотрим пример кода для записи задачи в очередь:
Функция ДобавитьЗадачуВОчередь(ИмяМетода, СтруктураПараметров) Экспорт
НоваяЗадача = РегистрыСведений.ОчередьЗадачКВнешнейБазе.СоздатьМенеджерЗаписи();
НоваяЗадача.ИдентификаторЗадачи = Новый УникальныйИдентификатор;
НоваяЗадача.Состояние = Перечисления.СостоянияЗадач.ВОчереди;
// Запаковываем параметры вызова в ХранилищеЗначения
СтруктураЗапуска = Новый Структура;
СтруктураЗапуска.Вставить("ИмяМетода", ИмяМетода);
СтруктураЗапуска.Вставить("Параметры", СтруктураПараметров);
НоваяЗадача.ПараметрыЗадачи = Новый ХранилищеЗначения(СтруктураЗапуска);
НоваяЗадача.Записать(Истина);
Возврат НоваяЗадача.ИдентификаторЗадачи;
КонецФункции
Этот подход гарантирует, что сервер не упадет от нехватки памяти, даже если одновременно 500 пользователей нажмут кнопку отправки данных. Все запросы выстроятся в контролируемую очередь и обработаются одним стабильным системным процессом.
---
Использование COM-технологий в экосистеме 1С постепенно уходит в прошлое и признается устаревшим архитектурным подходом (legacy). COM жестко привязывает серверную инфраструктуру к операционной системе Windows, порождает частые проблемы с разрядностью библиотек (32-бит против 64-бит) и часто приводит к неконтролируемым утечкам оперативной памяти на сервере приложений.
Наиболее надежный, быстрый и современный способ решить задачу совместного доступа — это разработка HTTP-сервисов на стороне принимающей базы данных. Рассмотрим этот вариант подробнее:
/get_balance, /create_order) и методы (GET, POST).HTTPСоединение.Посмотрим на пример отправки запроса к HTTP-сервису из кода 1С:
// Настраиваем параметры подключения к веб-серверу
Сервер = "192.168.1.100";
Порт = 80;
Пользователь = "ExchangeUser";
Пароль = "SuperSecurePassword123";
// Создаем HTTP-соединение. Веб-сервер автоматически управляет пулом HTTP-сессий!
Соединение = Новый HTTPСоединение(Сервер, Порт, Пользователь, Пароль);
// Формируем запрос
Запрос = Новый HTTPЗапрос("/BP_Exchange/hs/v1/get_balance");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// Передаем параметры в формате JSON
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("КодКонтрагента", "00-000125");
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
СтрокаJSON = ЗаписьJSON.Закрыть();
Запрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Попытка
Ответ = Соединение.ОтправитьДляАнализа(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Обрабатываем успешный ответ
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
Результат = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Дальнейшая работа с полученными данными
Иначе
ВызватьИсключение "Ошибка сервера: " + Ответ.КодСостояния;
КонецЕсли;
Исключение
ЗаписатьЛогОшибок(ОписаниеОшибки());
КонецПопытки;
Преимущества перехода на HTTP-сервисы огромны:
rphost на стороне COM-сервера.---
Если вы всё же вынуждены использовать классический COM (например, нет возможности опубликовать базу на веб-сервере или внести изменения в конфигурацию внешней базы), то лучшим системным решением для стабилизации работы будет вынос COM-коннектора в выделенное приложение **COM+** в Windows.
Разберем по шагам, как настроить эту схему:
dcomcnfg в строке выполнения.Службы компонентов -> Компьютеры -> Мой компьютер -> Приложения COM+.Создать -> Приложение.1C_COMConnector.dllhost.exe, а не внутри рабочего процесса 1С rphost.exe.Компоненты (Components), нажмите Создать -> Компонент и зарегистрируйте библиотеку внешнего соединения 1С comcntr.dll (она находится в каталоге установленной платформы 1С, например, C:\Program Files\1cv8\8.3.XX.XXXX\bin\comcntr.dll).Что мы получаем в результате этой настройки:
dllhost.exe в операционной системе Windows. Рабочие процессы самого сервера 1С (rphost) продолжат работать в штатном режиме, и пользователи этого даже не заметят.Каждое из рассмотренных решений имеет свои плюсы и минусы. Для быстрых доработок «на коленке» отлично подойдет настройка встроенного PoolCapacity для коннектора. Для крупных промышленных систем с повышенными требованиями к отказоустойчивости рекомендуется использовать асинхронный паттерн очереди задач либо полностью переходить на современные HTTP-сервисы.