При интеграции 1С со сторонними сервисами (веб-сервисы, REST API, внешние компоненты, COM-объекты) разработчики часто сталкиваются с ситуацией, когда сторонний ресурс перестает отвечать. При синхронном вызове интерфейс 1С полностью блокируется («зависает»), а пользователь не может продолжить работу или отменить действие. Разберем, как правильно настраивать время ожидания (таймаут) для различных способов интеграции и как предотвратить блокировку пользовательского сеанса.
По умолчанию, если таймаут соединения не задан явно (равен 0), платформа ожидает ответ до тех пор, пока операционная система или сетевое оборудование не разорвут TCP-соединение. В зависимости от сетевых настроек это ожидание может длиться от десятков минут до нескольких часов.
Рассмотрим распространенную ошибку: попытку задать таймаут свойству созданного объекта WSПрокси. В платформе 1С свойство WSПрокси.Таймаут доступно только для чтения. Попытка присвоить ему значение после создания объекта (например, Прокси.Таймаут = 10;) приведет к ошибке. Время ожидания необходимо передавать в момент инициализации объекта.
Проанализируем два способа инициализации веб-сервисов и правильную передачу параметра времени ожидания.
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 API, время ожидания соединения задается шестым параметром конструктора HTTPСоединение:
ТаймаутСекунд = 5;
Соединение = Новый HTTPСоединение("api.partner.ru", 443, "user", "pass", , ТаймаутСекунд, Новый ЗащищенноеСоединениеOpenSSL());
Запрос = Новый HTTPЗапрос("/get_discount?id=" + НоменклатураGUID);
Попытка
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Обработка успешного ответа
КонецЕсли;
Исключение
// Сюда попадем при недоступности сервера или превышении времени таймаута
Сообщить("Сервис временно недоступен: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Когда вызов стороннего сервиса нужен пользователю непосредственно в момент оформления документа (например, расчет скидки на кассе), но нельзя допустить «зависания» интерфейса, применим паттерн контролируемого синхронного ожидания через ФоновыеЗадания.
Разберем по шагам логику реализации:
ФоновыеЗадания.ОжидатьЗавершения().Посмотрим на пример кода серверной процедуры:
ПараметрыПроцедуры = Новый Массив;
ПараметрыПроцедуры.Добавить(Номенклатура);
// Запускаем фоновое задание
Задание = ФоновыеЗадания.Выполнить("ИнтеграцияСервер.ПолучитьСкидкуПартнера", ПараметрыПроцедуры, КлючЗадания, "Запрос скидки");
МассивЗаданий = Новый Массив;
МассивЗаданий.Добавить(Задание);
Попытка
// Ожидаем завершения максимум 3 секунды
ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий, 3);
// Если задание выполнено успешно, получаем результат
Результат = Задание.ПолучитьСообщенияПользователю();
// Либо считываем сохраненный результат из временного хранилища
Исключение
// Таймаут превышен или фоновое задание упало с ошибкой
Попытка
Задание.Отменить();
Исключение
// Задание уже завершено или отменено
КонецПопытки;
// Возвращаем дефолтное значение и не задерживаем пользователя
Скидка = 0;
КонецПопытки;
В платформе 1С для вызовов методов COMОбъект синтаксический таймаут не предусмотрен. Если внешний COM-сервер блокирует поток исполнения внутри своей C/C++ библиотеки, поток сеанса 1С зависнет бессрочно.
Для безопасной работы с нестабильными COM-библиотеками рекомендуется: