Вопрос проверяет, умеешь ли ты делать сетевые запросы устойчивыми: повторять запросы правильно, не создавая лишнюю нагрузку и не ломая данные.
Retry-логика — это повтор запроса при временных ошибках (например, нестабильная сеть или 5xx). Обычно задают максимальное число попыток, задержку между ними и условия, при которых можно повторять. Хорошая практика — использовать exponential backoff и добавить jitter, чтобы много клиентов не “стреляли” одновременно. Важно различать ошибки: 4xx чаще не ретраят (кроме 429), а запросы с изменением данных повторяют только если это безопасно.
Retry нужен не “на всё подряд”, а как контролируемая стратегия.
Определение: Retry — повторная попытка выполнить запрос после ошибки, по заданным правилам (сколько раз, с какой задержкой, при каких статусах).
Сеть/таймауты
TypeError у fetch (сетевой обрыв), ECONNRESET (в окружениях с Node), таймауты.
HTTP-коды
Можно ретраить: 502, 503, 504 (часто временно), иногда 500 (зависит от API).
Осторожно: 429 Too Many Requests — обычно нужно уважать Retry-After.
Обычно не ретраят: 400, 401, 403, 404 (логическая/авторизационная проблема, повтор не поможет).
Exponential backoff
1-я попытка: 200–500мс
2-я: ~400–1000мс
3-я: ~800–2000мс
Jitter
Добавляет случайность, чтобы тысячи клиентов не повторили запрос в одну и ту же миллисекунду.
async function fetchWithRetry(url, options = {}, cfg = {}) {
const {
retries = 3,
baseDelayMs = 300,
shouldRetry = (res, err) =>
!!err || (res && [502, 503, 504].includes(res.status)),
} = cfg;
for (let attempt = 0; attempt <= retries; attempt++) {
try {
const res = await fetch(url, options);
if (!shouldRetry(res, null) || attempt === retries) return res;
const delay = baseDelayMs * 2 ** attempt;
const jitter = Math.random() * 0.3 * delay;
await new Promise(r => setTimeout(r, delay + jitter));
} catch (err) {
if (attempt === retries || !shouldRetry(null, err)) throw err;
const delay = baseDelayMs * 2 ** attempt;
await new Promise(r => setTimeout(r, delay));
}
}
}
Идемпотентность
GET обычно безопасно ретраить.
POST/PATCH могут создать дубли (например, двойная покупка), поэтому нужна защита.
Защита от дублей
Используют Idempotency-Key (если API поддерживает) или client-generated requestId.
Таймаут на попытку
Каждая попытка должна иметь свой таймаут, иначе retry бессмысленен.
Границы
Максимум попыток и максимальная общая длительность (например, не больше 5–10 секунд).
Retry-логика хороша для временных ошибок и нестабильной сети, но должна быть ограниченной, с backoff+jitter, и учитывать безопасность повторов для запросов, меняющих данные.