Как настроить таймаут и избежать зависания 1С при вызове внешних веб-сервисов и COM-объектов?

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

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

Причина зависания и особенности свойства Таймаут в WSПрокси

По умолчанию, если таймаут соединения не задан явно (равен 0), платформа ожидает ответ до тех пор, пока операционная система или сетевое оборудование не разорвут TCP-соединение. В зависимости от сетевых настроек это ожидание может длиться от десятков минут до нескольких часов.

Рассмотрим распространенную ошибку: попытку задать таймаут свойству созданного объекта WSПрокси. В платформе 1С свойство WSПрокси.Таймаут доступно только для чтения. Попытка присвоить ему значение после создания объекта (например, Прокси.Таймаут = 10;) приведет к ошибке. Время ожидания необходимо передавать в момент инициализации объекта.

Установка таймаута при работе с SOAP веб-сервисами

Проанализируем два способа инициализации веб-сервисов и правильную передачу параметра времени ожидания.

1. Использование статических WS-ссылок из дерева метаданных:

В методе СоздатьWSПрокси таймаут (в секундах) передается пятым параметром:


Функция ПолучитьПроцентПартнера(Номенклатура) Экспорт
    ГУИД = Строка(Номенклатура.УникальныйИдентификатор());
    ТаймаутСекунд = 10; // Время ожидания ответа
    
    Попытка
        // 5-й параметр — таймаут в секундах
        Прокси = WSСсылки.Обмены.СоздатьWSПрокси("sitepr", "siteprSoap", "siteprSoapPort", , ТаймаутСекунд);
        Прокси.Пользователь = "exchange";
        Прокси.Пароль = "pass";
        
        Ответ = Прокси.ПолучитьПроцент(ГУИД);
        Возврат Число(Ответ);
    Исключение
        // При превышении таймаута управление сразу переходит в блок исключения
        ЗаписьЖурналаРегистрации("Интеграция с веб-сервисом", УровеньЖурналаРегистрации.Предупреждение, , , ОписаниеОшибки());
        Возврат 0;
    КонецПопытки;
КонецФункции

2. Динамическое создание WS-соединения через WSОпределения:

При динамическом подключении важно указывать таймаут как при получении WSDL-схемы (объект WSОпределения), так и при создании WSПрокси, иначе зависание произойдет еще до выполнения основного метода:


ТаймаутСекунд = 10;
Определения = Новый WSОпределения(АдресWSDL, Пользователь, Пароль, , ТаймаутСекунд);
Прокси = Новый WSПрокси(Определения, URIПространстваИмен, ИмяСервиса, ИмяПорта, , ТаймаутСекунд);

Установка таймаута для REST и HTTP-запросов (HTTPСоединение)

Если интеграция построена на REST/HTTP API, время ожидания соединения задается шестым параметром конструктора HTTPСоединение:


ТаймаутСекунд = 5;
Соединение = Новый HTTPСоединение("api.partner.ru", 443, "user", "pass", , ТаймаутСекунд, Новый ЗащищенноеСоединениеOpenSSL());
Запрос = Новый HTTPЗапрос("/get_discount?id=" + НоменклатураGUID);

Попытка
    Ответ = Соединение.Получить(Запрос);
    Если Ответ.КодСостояния = 200 Тогда
        // Обработка успешного ответа
    КонецЕсли;
Исключение
    // Сюда попадем при недоступности сервера или превышении времени таймаута
    Сообщить("Сервис временно недоступен: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;

Использование фоновых заданий для контролируемого ожидания

Когда вызов стороннего сервиса нужен пользователю непосредственно в момент оформления документа (например, расчет скидки на кассе), но нельзя допустить «зависания» интерфейса, применим паттерн контролируемого синхронного ожидания через ФоновыеЗадания.

Разберем по шагам логику реализации:

  1. Запускаем выполнение метода интеграции в фоновом задании на сервере.
  2. Ожидаем завершения фонового процесса с жестко заданным лимитом времени с помощью метода ФоновыеЗадания.ОжидатьЗавершения().
  3. Если за отведенное время задание не вернуло результат, отменяем фоновое задание и продолжаем работу без внешних данных (например, подставляем базовую розничную цену).

Посмотрим на пример кода серверной процедуры:


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

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

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

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

Особенности работы с COM-объектами

В платформе 1С для вызовов методов COMОбъект синтаксический таймаут не предусмотрен. Если внешний COM-сервер блокирует поток исполнения внутри своей C/C++ библиотеки, поток сеанса 1С зависнет бессрочно.

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

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