Как прервать зависшее соединение с веб-сервисом в 1С:Предприятии?

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

При интеграции систем «1С:Предприятие» с внешними веб-сервисами разработчики часто сталкиваются со следующей проблемой: если удаленный сервер выключен, перегружен или недоступен из-за проблем с сетью, стандартный сетевой запрос «намертво» блокирует работу программы. Пользователь видит песочные часы, интерфейс перестает реагировать на любые действия, а принудительно закрыть зависший процесс удается только через диспетчер задач.

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

Проанализируем ситуацию на классическом примере из практики. Разработчик пытается отправить запрос к стороннему API:


HTTPСоединение = Новый HTTPСоединение(АдресСервера);
HTTPЗапрос = Новый HTTPЗапрос(АдресЗапроса);
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);

Если сервер по указанному адресу недоступен, этот код заблокирует сеанс. Выясним, почему это происходит и как решить проблему по шагам.

Способ 1. Явное указание таймаута в конструкторе (базовый уровень)

По умолчанию, если в конструкторе объекта HTTPСоединение не указать время ожидания, платформа 1С будет использовать системные настройки операционной системы. В Windows и Linux таймаут TCP-соединения по умолчанию может достигать нескольких минут. Для пользователя это выглядит как глухое зависание программы.

Решение заключается в явной установке таймаута в секундах. Это шестой параметр конструктора HTTPСоединение. Посмотрим на пример кода, где мы ограничиваем время ожидания соединения пятью секундами:


Сервер = "api.example.com";
Порт = 443;
Пользователь = "User1C";
Пароль = "SecretPassword";
Прокси = Неопределено;
Таймаут = 5; // Время ожидания ответа в секундах

Попытка
    HTTPСоединение = Новый HTTPСоединение(Сервер, Порт, Пользователь, Пароль, Прокси, Таймаут);
    HTTPЗапрос = Новый HTTPЗапрос("/v1/get_data");
    HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
    
    КодСостояния = HTTPОтвет.КодСостояния;
    Если КодСостояния = 200 Тогда
        // Обрабатываем успешный ответ
    Иначе
        ВызватьИсключение "Ошибка сервера. Код ответа: " + КодСостояния;
    КонецЕсли;
Исключение
    // Сюда мы попадем, если сервер не ответил в течение 5 секунд или произошла другая сетевая ошибка
    ИнформацияОбОшибке = ИнформацияОбОшибке();
    ЗаписьЖурналаРегистрации("ИнтеграцияСВебСервисом", УровеньЖурналаРегистрации.Предупреждение,,, 
        ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
        
    ПоказатьПредупреждение(, "Не удалось связаться с сервером. Пожалуйста, повторите попытку позже.");
КонецПопытки;

Важно: Всегда оборачивайте сетевые вызовы в конструкцию Попытка ... Исключение. При превышении таймаута платформа генерирует исключение, которое необходимо корректно перехватить, записать в журнал регистрации и вывести пользователю понятное сообщение без аварийного завершения сеанса.

Способ 2. Выполнение запросов в фоновом режиме (асинхронный подход)

Даже если установить таймаут в 5 секунд, для интерактивного приложения на управляемых формах это время может быть критичным. Пользователь будет ощущать неприятные «фризы» интерфейса при каждом сетевом сбое. Чтобы избежать блокировки основного потока, рассмотрим запуск тяжелых сетевых задач в фоне.

Мы можем вынести процедуру отправки HTTP-запроса в фоновое задание. В этом случае основной сеанс пользователя останется полностью отзывчивым, а для контроля выполнения мы будем использовать программный лимит времени.

Разберем схему реализации:

  1. Создадим экспортную процедуру в общем серверном модуле (например, ИнтеграцияСервер), которая будет выполнять HTTP-запрос.
  2. Запустим эту процедуру через менеджер фоновых заданий.
  3. Будем ожидать завершения работы задания в течение фиксированного времени с помощью метода ОжидатьЗавершенияВыполнения().

Пример кода для запуска и контроля фонового задания:


ПараметрыПроцедуры = Новый Структура;
ПараметрыПроцедуры.Вставить("АдресЗапроса", "/v1/heavy_report");

МассивПараметров = Новый Массив;
МассивПараметров.Добавить(ПараметрыПроцедуры);

// Запускаем фоновое задание на сервере
НовоеЗадание = ФоновыеЗадания.Выполнить("ИнтеграцияСервер.ВыполнитьHTTPЗапрос", МассивПараметров, "ЗапросКВебСервису");

МассивЗаданий = Новый Массив;
МассивЗаданий.Добавить(НовоеЗадание);

ТаймаутОжидания = 10; // Ждем ответа не более 10 секунд

Попытка
    // Метод ожидает завершения выполнения задания. Если время истекает, вызывается исключение.
    ФоновыеЗадания.ОжидатьЗавершенияВыполнения(МассивЗаданий, ТаймаутОжидания);
    
    // Получаем результат работы из временного хранилища или настроенных реквизитов
    Сообщить("Запрос успешно выполнен!");
Исключение
    // Если задание не успело выполниться, принудительно отменяем его, чтобы освободить рабочий процесс
    НовоеЗадание.Отменить();
    ВызватьИсключение "Превышено время ожидания ответа от веб-сервиса. Операция прервана.";
КонецПопытки;

Этот подход гарантирует, что даже при полном зависании сетевого сокета на уровне операционной системы, сеанс 1С принудительно убьет зависший поток по истечении таймаута.

Способ 3. Готовые механизмы БСП (Библиотека стандартных подсистем)

Если конфигурация разработана на базе современных стандартов 1С, в ней гарантированно присутствует Библиотека стандартных подсистем (БСП). Разработчикам нет необходимости вручную прописывать логику ожидания фоновых заданий. Для этих целей отлично подходит подсистема «Длительные операции».

Использование БСП дает несколько весомых преимуществ:

Для запуска длительного сетевого обмена через БСП достаточно использовать функции ДлительныеОперации.ЗапуститьВыполнениеНаСервере() и ДлительныеОперации.ОжидатьЗавершения() в соответствии с документацией к вашей версии библиотеки.

Способ 4. Архитектурные рекомендации по проектированию веб-сервисов

Проанализируем рекомендации фирмы 1С, опубликованные на ИТС, касательно проектирования интеграционных решений. Настройка таймаутов должна зависеть от решаемой бизнес-задачи:

  1. Быстрая проверка связи («пинг»): Не стоит использовать для этой цели системную утилиту ping (протокол ICMP), так как сетевые экраны на пути к веб-серверу могут блокировать ICMP-пакеты, при этом сам веб-сервер будет исправно работать по портам 80/443. Вместо этого выполняйте быстрый пустой GET или HEAD-запрос с жестким таймаутом в 2–3 секунды. Если за это время сервер не ответил, продолжать работу бессмысленно.
  2. Регулярный синхронный обмен: Для рядовых запросов (получение остатков, создание контрагента) оптимальный таймаут составляет 15–30 секунд. Если система не укладывается в эти рамки, это признак проблем с производительностью базы данных или канала связи.
  3. Тяжелые аналитические запросы: Если веб-сервис выполняет сложную обработку данных, которая может занимать минуты, использовать синхронное ожидание — грубая ошибка. Правильным архитектурным решением будет переход на асинхронное API.

В рамках асинхронного API взаимодействие строится следующим образом:

Способ 5. Альтернатива через COM-объекты (для устаревших платформ)

В старых версиях платформы 1С:Предприятие (например, ранних релизах 8.2 или 8.3) встроенное HTTPСоединение могло вести себя нестабильно при обрывах связи, игнорируя системные таймауты. В таких ситуациях разработчики успешно применяют системные библиотеки Windows через COM-соединение.

Объект WinHttp.WinHttpRequest.5.1 предоставляет гибкие возможности настройки таймаутов на каждом этапе сетевого обмена:


Попытка
    WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
    
    // Параметры SetTimeouts: 
    // 1. Разрешение имени (DNS-запрос) - 5 сек
    // 2. Установка TCP-соединения - 5 сек
    // 3. Отправка данных на сервер - 10 сек
    // 4. Ожидание ответа сервера - 30 сек
    WinHttp.SetTimeouts(5000, 5000, 10000, 30000);
    
    // Третий параметр "Истина" включает асинхронный режим отправки
    WinHttp.Open("GET", "https://api.example.com/data", Ложь);
    WinHttp.Send();
    
    КодCтатуса = WinHttp.Status;
    Если КодCтатуса = 200 Тогда
        ТекстОтвета = WinHttp.ResponseText;
    КонецЕсли;
Исключение
    Сообщить("Ошибка COM-соединения: " + ОписаниеОшибки());
КонецПопытки;

Использование COM-объектов позволяет реализовать метод abort(), который можно вызвать из параллельного потока для мгновенного принудительного разрыва установленного сетевого сокета, если программа приняла решение не ожидать окончания операции.

Подводя итоги нашего разбора, отметим: стабильная интеграция невозможна без грамотного управления лимитами времени. Начните с установки параметра Таймаут в конструкторе HTTPСоединение, а для критически важных интерфейсных окон переводите запросы в фоновый режим выполнения. Это убережет ваших пользователей от зависаний системы и сделает работу с внешними сервисами надежной.

← На главную