Обработка сетевых таймаутов и реализация Retry Policy в 1С:Предприятие
При интеграциях через нестабильные каналы связи возникают проблемы:
- Ошибки
Превышен таймаут ожидания ответа сервиса (Gateway Timeout 504). - Всплеск ошибок
502 Bad Gatewayи503 Service Unavailableпри перезагрузке внешнего сервиса. - Лавинообразная перегрузка целевого сервера одновременными повторными запросами (Retry Storm).
- Аварийная остановка регламентных фоновых заданий из-за единичного сетевого сбоя.
1. Паттерн Exponential Backoff with Jitter (Экспоненциальная задержка со случайным смещением)
При возникновении сетевой ошибки или получении статусов 429 / 502 / 503 / 504 система не должна повторять вызов немедленно. Интервал повтора рассчитывается по формуле: Интервал = (2 ^ НомерПопытки) + СлучайноеЧисло.
2. Программная реализация универсальной Retry-политики в 1С
&НаСервере
Функция ВыполнитьHTTPЗапросСПовтором(HTTPСоединение, HTTPЗапрос, Метод = "GET", МаксПопыток = 4) Экспорт
ТекущаяПопытка = 1;
БазоваяЗадержка = 1; // в секундах
Пока ТекущаяПопытка <= МаксПопыток Цикл
Попытка
HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод(Метод, HTTPЗапрос);
// Успешный ответ
Если HTTPОтвет.КодСостояния >= 200 И HTTPОтвет.КодСостояния < 300 Тогда
Возврат HTTPОтвет;
// Ошибки, при которых имеет смысл повторить вызов (Transient Errors)
ИначеЕсли HTTPОтвет.КодСостояния = 429 ИЛИ HTTPОтвет.КодСостояния >= 500 Тогда
ВызватьИсключение СтрШаблон("HTTP статус %1", HTTPОтвет.КодСостояния);
Иначе
// Клиентские ошибки 4xx (кроме 429) повторять бессмысленно
Возврат HTTPОтвет;
КонецЕсли;
Исключение
Если ТекущаяПопытка = МаксПопыток Тогда
ЗаписьЖурналаРегистрации("RETRY_POLICY", УровеньЖурналаРегистрации.Ошибка,,,
СтрШаблон("Все %1 попыток исчерпаны: %2", МаксПопыток, ОписаниеОшибки()));
ВызватьИсключение "Сервис недоступен после нескольких попыток: " + ОписаниеОшибки();
КонецЕсли;
// Расчет задержки: 2^(попытка) + random jitter
Генератор = Новый ГенераторСлучайныхЧисел();
СлучайныйДжиттер = Генератор.СлучайноеЧисло(100, 800) / 1000;
ВремяОжидания = Pow(2, ТекущаяПопытка) * БазоваяЗадержка + СлучайныйДжиттер;
ЗаписьЖурналаРегистрации("RETRY_POLICY", УровеньЖурналаРегистрации.Предупреждение,,,
СтрШаблон("Попытка %1 завершилась сбоем. Пауза %2 сек.", ТекущаяПопытка, ВремяОжидания));
// Пауза выполнения потока
ПриостановитьРаботу(ВремяОжидания);
ТекущаяПопытка = ТекущаяПопытка + 1;
КонецПопытки;
КонецЦикла;
КонецФункции3. Использование Circuit Breaker (Автоматический размыкатель цепи)
Если внешний сервис падает на длительное время, 1С должна «разомкнуть цепь» (сохранить статус сбоя в регистре сведений) и блокировать вызовы на 5-10 минут, не создавая бесполезной нагрузки на сеть.
Частые вопросы (FAQ)
Что такое Jitter и зачем он нужен при повторах?
Jitter — это случайное отклонение во времени задержки. Без него тысячи параллельных фоновых заданий 1С будут синхронно повторять запросы в одну и ту же миллисекунду, повторно обрушивая восстанавливающийся сервер.
Имеет ли смысл повторять POST-запросы без идемпотентности?
Повторять неидемпотентные POST-запросы (создание платежа, проведение чека) опасно без передачи уникального ключа идемпотентности (Idempotency-Key), иначе операция выполнится дважды.
Какой оптимальный таймаут указывать в конструкторе HTTPСоединение?
Для интерактивных запросов пользователей таймаут не должен превышать 5-10 секунд. Для тяжелых фоновых обменов — от 30 до 60 секунд.
Как перехватить заголовок Retry-After от сервера?
Если сервер вернул 429 или 503, прочитайте значение HTTPОтвет.Заголовки.Получить('Retry-After') и используйте указанное в нем количество секунд для паузы.