Кабинет продавца на Авито часто ловит 502 от балансировщика в первые секунды после выката. Хочется повторять запрос, но не всякий.
Напишите retryFetch(fetchFn, url, options = {}, attempts = 0). fetchFn ведёт себя как fetch: промис с ответом { ok, status } или отказ при сетевой ошибке. attempts — сколько раз можно повторить после первой попытки.
Правила: ответ с ok: true — сразу resolve с ответом. Метод PUT в любом регистре не повторяем: правка цены объявления не должна уйти дважды. Ответы 401 и 403 не повторяем: без прав повтор не поможет. Остальные неудачные ответы и сетевые ошибки повторяем, пока есть попытки.
Когда повторять нельзя или нечем, промис отклоняется последним ответом или последней ошибкой, без обёрток.
В работе: Запросы кабинета продавца во время выката: 0,5 % ответов 502 за первые 10 секунд.
Пример 1: 502, 502, 200 — успех с третьей попытки
"GET", 3, [502, 502, 200]
["ok:200", 3, "GET"]
Пример 2: попытки кончились — последний ответ
"GET", 2, [500, 502, 503, 200]
["rej:503", 3, "GET"]
retryFetch — тест вызывает её сам. Таймеры и Date в тестах ненастоящие: время идёт по команде теста, поэтому setTimeout на 5 секунд проверяется мгновенно. Тестов 9: 2 открыты выше, остальные приходят после старта подхода. Лимит — 2 с на тест.
function retryFetch(fetchFn, url, options = {}, attempts = 0) // → Promise<Response>
Источник: Авито, задача retryFetch из репозитория кандидата с задачами собеседований, 2024. Условие пересказано своими словами.
Ожидаемый ответ не нужен: покажем, что вернула функция.
Здесь появится результат отправки.