Почему при записи документа через COM возникает ошибка «Удаленный хост принудительно разорвал существующее подключение» (10054), хотя транзакция в базе-приемнике завершается успешно?

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

Работа с COM-соединениями в среде 1С часто преподносит неприятные сюрпризы, особенно когда речь идет о параллельном проведении документов в двух разных системах. Ситуация, когда в базе-источнике вылетает исключение 10054, а в базе-приемнике данные успешно записываются и проводятся, является классическим примером «рассинхрона» подтверждения транзакции. В этой статье мы подробно проанализируем, почему это происходит, разберем технические причины на уровне сети и платформы, а также рассмотрим способы устранения данной проблемы.

Природа возникновения ошибки 10054 и рассинхронизация данных

Разберем детально механизм взаимодействия. Когда мы вызываем метод проведения документа в удаленной базе через COM-объект, цепочка событий выглядит следующим образом:

  1. База-источник отправляет запрос в базу-приемник через COM-интерфейс.
  2. База-приемник получает запрос, открывает транзакцию, выполняет все проверки и записывает данные в СУБД.
  3. Транзакция в базе-приемнике фиксируется (Commit).
  4. Критический момент: После фиксации база-приемник должна отправить обратно в базу-источник флаг успешного выполнения.
  5. Если в этот микроскопический промежуток времени сетевое соединение разрывается, база-источник получает ошибку Удаленный хост принудительно разорвал существующее подключение (10054).

В результате мы имеем патовое состояние: в Журнале Регистрации базы-приемника всё чисто (подключились, провели, отключились), а в базе-источнике срабатывает блок Исключение, и локальная транзакция откатывается. Проанализируем основные причины, которые могут приводить к такому поведению.

Влияние версии платформы и ошибки управления памятью

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

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

Настройка сетевых таймаутов и параметров Keep-Alive

Часто проблема кроется в настройках операционной системы и сетевого оборудования. Проанализируем ситуацию: если проведение документа в базе-приемнике занимает значительное время (например, более 30 секунд из-за сложных расчетов в обработке ОбработкаПроведения), сетевое оборудование или брандмауэр может посчитать соединение неактивным (IDLE) и закрыть его.

Для решения этой проблемы необходимо проверить параметры Keep-Alive в реестре Windows на обоих серверах (источнике и приемнике). Разберем, какие ключи за это отвечают:

Путь в реестре: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Если время выполнения транзакции в 1С превышает системные лимиты ожидания пакета подтверждения (ACK), сетевой стек разорвет связь именно в тот момент, когда приложение попытается отправить ответ после завершения записи данных.

Таймауты DCOM и конфигурация соединений

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

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

Диагностика через Журнал Регистрации и ТЖ

Для выявления закономерности рекомендуется проанализировать длительность входящих сеансов в базе-приемнике. Посмотрим на пример данных из Журнала Регистрации:

  1. Найдите записи о COM-подключении, которое в источнике завершилось ошибкой.
  2. Сравните время начала события Сеанс.Начало и время фиксации транзакции.
  3. Если длительность выполнения превышает стандартные 30 секунд, скорее всего, вы сталкиваетесь с сетевым таймаутом.

Если стандартных логов недостаточно, придется настроить Технологический Журнал (ТЖ) на стороне источника. Нас интересуют события EXCP (исключения) и COM. Это позволит увидеть, на какой именно инструкции внутри 1С происходит обрыв и какой сетевой вызов возвращает код ошибки 10054.

Рекомендации по изменению архитектуры обмена

Если проблему не удается решить настройкой сети или обновлением платформы, стоит рассмотреть программные методы предотвращения рассинхрона данных. Рассмотрим несколько вариантов:

1. Двухфазная фиксация (имитация)

Вместо прямой попытки проведения документа, разделим процесс на два этапа:

  1. Записываем документ в базе-приемнике без проведения (или в специальном статусе "Подготовлен").
  2. Если запись прошла успешно и ответ вернулся, вторым коротким вызовом вызываем метод Записать(РежимЗаписиДокумента.Проведение). Это минимизирует время удержания COM-соединения в активной транзакции и снижает риск разрыва по таймауту.

2. Переход с Application на COMConnector

Если вы используете запуск полноценного приложения через V83.Application, попробуйте переключиться на V83.COMConnector. Разберем разницу:

Пример использования COMConnector для стабильной записи:


// Инициализация соединения
Connector = Новый COMОбъект("V83.COMConnector");
Connection = Connector.Connect("Srvr='ServerName';Ref='BaseName';Usr='Login';Pwd='Password';");

Попытка
    УдаленныйДокумент = Connection.Документы.РеализацияТоваровУслуг.НайтиПоНомеру(НомерДок, ДатаДок);
    Если Не УдаленныйДокумент.Пустая() Тогда
        ОбъектДок = УдаленныйДокумент.ПолучитьОбъект();
        ОбъектДок.Записать(Connection.FixedStruct.РежимЗаписиДокумента.Проведение);
    КонецЕсли;
Исключение
    // Обработка ошибки 10054
    ЗаписьЖурналаРегистрации("COM_Exchange", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;

3. Асинхронная очередь

Самый надежный способ — отказаться от проведения "в реальном времени" через COM. Рассмотрим схему с очередью:

  1. В базе-источнике создается запись в регистре сведений "ОчередьОбмена".
  2. Фоновое задание раз в минуту считывает эти записи и пытается выполнить действия в удаленной базе.
  3. При возникновении ошибки 10054 задание просто повторит попытку позже, предварительно проверив — а не провелся ли документ в прошлый раз (проверка статуса документа в приемнике перед действием).

Заключение: Ошибка 10054 при успешной транзакции в COM — это следствие того, что физический уровень связи (TCP/IP) обрывается раньше, чем логический уровень (COM-ответ 1С) успевает сообщить об успехе. Тщательная настройка параметров Keep-Alive, использование COMConnector вместо Application и переход к транзакционной устойчивости (проверка состояния перед повторной записью) позволят навсегда забыть об этой проблеме.

← На главную