Таймауты при работе с внешними ресурсами

#std748

Область применения: управляемое приложение, обычное приложение.

1. При работе с внешними ресурсами с помощью объектов WSОпределения, WSПрокси, HTTPСоединение, FTPСоединение, ИнтернетПочтовыйПрофиль следует задавать таймаут – предельное время  ожидания выполнения операции. В противном случае, в результате бесконечного ожидания программа зависнет или часть функционала программы станет недоступна.

Установка таймаута является защитой от целого ряда внешних факторов:

Например, при получении описания веб-сервиса и вызове его операций – если удаленная сторона долго не отвечает (например, выключена, находится на обслуживании или возникли временные неполадки), ожидание ответа может длиться бесконечно. Поэтому если веб-сервис был вызван в результате интерактивных действий пользователя, то внешне будет выглядеть так, что «программа зависла»; а если веб-сервис вызывается из регламентного задания, то связанная с ним часть функционала программы может стать недоступна.

2. В общем виде, время выполнения операции с внешними ресурсами складывается из шести этапов:

Например, при таймауте в 60 секунд программа и вызываемый внешний ресурс должны успеть выполнить шесть выше перечисленных этапов операции, иначе соединение будет разорвано, а передача данных прервана. Однако если в процессе выполнения операции возникнет сбой, то система и/или пользователь будет зря ожидать 60 секунд.

Поэтому величину таймаута рекомендуется определять, исходя из ожидаемого времени выполнения конкретной операции:

Подобнее о рекомендуемых величинах таймаута для различных операций см. в таблице п. 4.

3. Рекомендации по снижению величин таймаута и повышению отзывчивости программы при работе с внешними ресурсами.

3.1. При разработке веб-сервисов, на операции которых предусмотрен таймаут более 20 секунд (ориентировочно), рекомендуется:

Пример вызова веб-сервиса.

Неправильно

Правильно

Реализация модуля веб-сервиса PingPong:

Функция Pong(Знач Параметр)
  Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Привет, %1'"), Параметр);
КонецФункции

Функция Ping()
  Возврат Истина; // Проверка связи
КонецФункции

Функция Pong(Знач Параметр)
  Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Привет, %1'"), Параметр);
КонецФункции

Реализация вызывающей стороны (без использования Библиотеки стандартных подсистем):

// Ждем не более минуты
PingPong = Новый WSПрокси(АдресВебСервиса, , , , , 60);
Результат = PingPong.Pong(НСтр("ru = 'Мяч'"));

// Ждем не более 3 секунд
PingPong = Новый WSПрокси(АдресВебСервиса, , , , , 3);
PingPong.Ping(); // проверка связи

// Сервис жив, далее работаем с ним и ждем не более минуты
PingPong = Новый WSПрокси(АдресВебСервиса, , , , , 60); 
Результат = PingPong.Pong(НСтр("ru = 'Мяч'"));

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

Пример реализации вызывающей стороны с использованием Библиотеки стандартных подсистем:

// Сделать контрольный вызов Ping и ждать не более минуты на дальнейших операциях.
PingPong = ОбщегоНазначения.WSПрокси(АдресВебСервиса,..., 60, Истина);
// Сервис точно жив, далее работаем с ним.
Результат = PingPong.Pong(НСтр("ru = 'Мяч'"));

3.2. Для других видов внешних ресурсов (не веб-сервисов) рекомендуется применять аналоги операции Ping. Например:

3.3. Веб-сервисы, операции, которых занимают объективно много времени из-за этапа Wait (т.е. долго отрабатывает само веб-приложение), и они не могут быть ускорены (оптимизированы) по объективным причинам, следует переводить на асинхронный режим выполнения:

Пример асинхронного вызова веб-сервиса.

Неправильно

Правильно

Реализация модуля веб-сервиса Long:

Функция GetData()
    Результат = <очень длительные вычисления>;
    Возврат Результат;
КонецФункции

Функция StartDoLong()
    // запуск фонового задания
    ИдентификаторОперации = ...
    // возвращаем идентификатор операции для отслеживания ее готовности
    Возврат ИдентификаторОперации;
КонецФункции

Функция IsReady(Знач ИдентификаторОперации)
    // проверяем, завершено ли фоновое задание по переданному идентификатору
    Готовность = ...
    Возврат Готовность;
КонецФункции

Функция GetData(Знач ИдентификаторОперации)
    Результат = <получаем уже готовый результат по переданному идентификатору >;
    Возврат Результат;
КонецФункции

Реализация вызывающей стороны:

Long = Новый WSПрокси(АдресВебСервиса, , , , , 600); // ждем 10 мин

Результат = Long.GetData();

Long = Новый WSПрокси(АдресВебСервиса, , , , , 600); // ждем 10 мин

ИдентификаторОперации = Long.StartDoLong();

Пока Не Long.IsReady(ИдентификаторОперации) Цикл
    <ждем определенный интервал времени>
КонецЦикла;
Результат = Long.GetData(ИдентификаторОперации);

* это лишь упрощенная схема реализации вызывающей стороны; в действительности,
код вызывающей стороны также должен быть реализован асинхронно с помощью включения
регламентного задания, либо периодического обработчика ожидания на клиенте,
который проверяет готовность и получает результат.

4. Рекомендуемые величины таймаутов для различных операций:

Операция  Таймаут (секунд)
Получение описания веб-сервиса  7
Проверка корректности введенного адреса, взаимодействие с менеджером сервиса в модели сервиса и прочие «быстрые» операции 10-20
Получение сведений об одном контрагенте, обмен сообщениями, отправка SMS, удаленное администрирование ИБ в модели сервиса 60-1201
Передача сообщений обмена данными через веб-сервис или получение файлов из внешнего ресурса до 1 Мб. 120-1801
Загрузка файлов более 1 Мб Если известен размер файла, то размер в мегабайтах * 1282, иначе предельное время загрузки, но не более 43200 3


1 Следует вызывать только после контрольной операции Ping.

2 Загрузка 1 мегабайта данных занимает 128 секунд, при скорости 64 кбит/с, т.к. сотовые операторы в определенных случаях ограничивают скорость загрузки этой величиной.

3 Таймаут продолжительностью 43200(12 часов) сек. является компромиссным решением, т.к. в случае нештатной ситуации процесс «отвиснет» на следующее утро и вернет управление, в отличие от полностью зависнувшей программы при неустановленном таймауте.