Как проверить, идет ли обмен по COM-соединению, и автоматически закрывать его при неактивности

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

Работа с внешними источниками данных через COM-соединение в 1С — это классический, но ресурсоемкий механизм. Основная проблема заключается в том, что каждое такое соединение потребляет значительный объем оперативной памяти и создает отдельный сеанс в целевой базе. Если соединение не закрывать вовремя, это может привести к нехватке лицензий, блокировкам при обновлении конфигурации (ошибка формата потока) и общему замедлению системы. Рассмотрим подробно, как реализовать механизм контроля активности соединения и его автоматического завершения по истечении заданного времени.

Анализ проблемы длительных COM-соединений

Процесс установки соединения через V83.COMConnector является длительным. Именно поэтому разработчики часто стремятся сохранить созданный объект в глобальной переменной, чтобы не тратить время на повторную авторизацию при каждом обращении. Однако "вечное" соединение — это плохая практика. Нам необходимо найти баланс: держать соединение открытым, пока пользователь активно с ним работает, и корректно разрывать его, если обращений не было, например, в течение 30 минут.

Проанализируем техническую сложность: стандартные средства 1С не позволяют напрямую "спросить" у объекта COMConnector, передает ли он данные в текущую секунду. Вызовы методов через COM происходят синхронно — пока выполняется запрос в другой базе, основной поток кода ожидает ответа. Следовательно, проверку нужно строить на логике "времени последнего обращения".

Реализация автоматического завершения через обработчик ожидания

Для решения задачи мы будем использовать встроенный механизм платформы — ПодключитьОбработчикОжидания. Разберем алгоритм: при каждом обращении к внешней базе мы будем "сбрасывать" таймер. Если таймер дотикал до конца — значит, за это время обращений не было, и объект можно уничтожить.

Рассмотрим правильную структуру размещения кода. Важно помнить, что в 1С (особенно в управляемом приложении или при использовании глобальных процедур в обычном приложении) обработчик ожидания имеет жесткие требования к расположению процедуры. Она должна быть экспортируемой и находиться либо в модуле приложения, либо в глобальном общем модуле на стороне клиента.

Выясним причину частой ошибки "Недопустимое значение параметра (параметр номер '1')". Она возникает, если система не может найти указанную процедуру в глобальной области видимости клиента. Рассмотрим пример реализации, который учитывает эти особенности.

Шаг 1. Объявление переменной

В модуле обычного приложения (или в специализированном общем модуле) объявим переменную для хранения соединения:

Перем ОбъектКА Экспорт; // Здесь хранится наше COM-соединение

Шаг 2. Процедура управления соединением

Создадим логику, которая будет запускать или перезапускать отсчет времени при каждом обращении к базе. Проанализируем код:


// Процедура вызывается каждый раз, когда нам нужно COM-соединение
Процедура СтартComСоединения() Экспорт
    // Если соединение уже установлено, сначала отключим старый таймер, чтобы начать отсчет заново
    Если ОбъектКА <> Неопределено Тогда
        ОтключитьОбработчикОжидания("глЗавершениеComСоединения");
    КонецЕсли;
    
    // Устанавливаем таймер на 1800 секунд (30 минут)
    // Параметр Однократно = Истина, так как нам нужен разовый запуск по истечении времени
    ПодключитьОбработчикОжидания("глЗавершениеComСоединения", 1800, Истина);
КонецПроцедуры

Шаг 3. Глобальный модуль-обертка

Чтобы избежать ошибок области видимости, создадим в Глобальном общем модуле (с галочкой "Глобальный" и "Клиент") процедуру-переходник:


Процедура глЗавершениеComСоединения() Экспорт
    // Вызываем реальную процедуру очистки из нашего модуля
    РаботаСВнешнимиБазами.ЗавершитьСеансCOM();
КонецПроцедуры

Шаг 4. Очистка объекта

В основном модуле (например, РаботаСВнешнимиБазами) пропишем само уничтожение объекта:


Процедура ЗавершитьСеансCOM() Экспорт
    // Присваивание Неопределено освобождает ссылку на COM-объект
    // Это инициирует закрытие сеанса в удаленной базе
    ОбъектКА = Неопределено; 
    ЗаписьЖурналаРегистрации("COM-соединение",,,,"Сеанс завершен по таймауту неактивности.");
КонецПроцедуры

Нюансы работы с памятью и блокировками

Проанализируем ситуацию, когда простого присвоения Неопределено недостаточно. В некоторых случаях Windows может удерживать процесс dllhost.exe (в котором работает COM) еще некоторое время. Если вам критично моментальное завершение для выполнения административных задач в другой базе, убедитесь, что в коде не осталось других ссылок на объекты, полученные из этого соединения (выборки, ссылки, документы).

Важный совет: всегда проверяйте состояние соединения перед использованием. Если переменная ОбъектКА равна Неопределено, вызывайте функцию подключения и сразу после этого — СтартComСоединения().

Альтернативный подход: отказ от COM в пользу навигационных ссылок

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

В современных версиях 1С (8.3) у каждого объекта есть уникальный адрес. Мы можем получить его в целевой базе и передать в текущую. Вместо открытия базы через OLE, можно использовать запуск системы с параметром или метод ПерейтиПоСсылке().

  1. В целевой базе получаем ссылку: ПолучитьНавигационнуюСсылку(Объект).
  2. Передаем эту строку (она выглядит как e1cib/data/Справочник.Номенклатура?ref=...) в основную базу.
  3. В основной базе используем системную команду для открытия внешней ссылки. Это запустит (или активирует уже открытое) окно другой базы и сразу отобразит нужную форму.

Такой подход полностью снимает проблему "Ошибка формата потока" и зависших сеансов, так как управление жизненным циклом приложения берет на себя сама платформа и операционная система, а не ваш программный код.

Резюме

Для надежной работы системы при использовании COM-соединений необходимо:

  1. Использовать обработчики ожидания для контроля таймаута неактивности.
  2. Размещать вызовы обработчиков в глобальных модулях для соблюдения требований контекста выполнения.
  3. При каждом обращении к объекту перезапускать таймер, отключая старый перед включением нового.
  4. Рассмотреть переход на HTTP-сервисы или навигационные ссылки, если задача позволяет отказаться от прямого управления объектами через COM, что значительно повысит стабильность системы.
← На главную