Что такое паттерн Retry и как его правильно использовать
Structured Java interview answer with junior, middle, and senior-level explanation.
🟢 Junior Level
Retry — автоматический повторный вызов сервиса при временной ошибке.
Вызов 1 → ошибка (timeout)
Retry 1 → ошибка (timeout)
Retry 2 → успех! ✅
Зачем: Временные ошибки бывают часто (сеть, таймаут, перегрузка). Retry даёт сервису время восстановиться.
🟡 Middle Level
Resilience4j Retry
RetryConfig config = RetryConfig.custom()
.maxAttempts(3) // 3 попытки
.waitDuration(Duration.ofSeconds(1)) // ждать 1 сек между попытками
.retryExceptions(TimeoutException.class, ConnectException.class)
.build();
Retry retry = Retry.of("backend", config);
Supplier<String> decorated = Retry.decorateSupplier(retry,
() -> backendService.call());
Exponential backoff
RetryConfig config = RetryConfig.custom()
.maxAttempts(5)
.waitDuration(Duration.ofMillis(500))
.intervalFunction(IntervalFunction.ofExponentialBackoff(500, 2.0))
.build();
// 500 = начальная задержка (мс), 2.0 = множитель (exponential).
// 500ms → 1000ms → 2000ms → 4000ms ...
// Попытки: 500ms → 1s → 2s → 4s → 8s
Типичные ошибки
- Retry для всех ошибок:
404 Not Found → retry бесполезен 500 Internal Error → retry может помочь Решение: retry только для retryable ошибок
🔴 Senior Level
Retry с jitter
// Jitter предотвращает thundering herd
// Thundering herd — когда множество клиентов одновременно повторяют вызов,
// создавая новый пик нагрузки. Jitter «размазывает» повторные вызовы во времени.
Random random = new Random();
long waitTime = baseDelay + random.nextInt((int)(baseDelay * 0.1)); // jitter 10% от delay
Production Experience
Spring Retry:
@Retryable(
value = {RetryableException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000, multiplier = 2)
)
// @Recover — метод, вызываемый когда все retry исчерпаны.
// Сигнатура: тот же тип возвращаемого значения + Exception как первый параметр.
public String callService(String input) {
return restTemplate.getForObject(url, String.class);
}
@Recover
public String recover(RetryableException e) {
return "fallback";
}
Best Practices
✅ Exponential backoff
✅ Jitter для предотвращения thundering herd
✅ Retry только для retryable ошибок
✅ Лимит попыток
✅ Fallback после всех retry
❌ Retry для 4xx ошибок
❌ Без backoff
❌ Без лимита попыток
❌ Retry для идемпотентных операций
🎯 Шпаргалка для интервью
Обязательно знать:
- Retry — автоматический повторный вызов при временной ошибке (timeout, network)
- Exponential backoff: 500ms → 1s → 2s → 4s — даёт сервису время восстановиться
- Jitter добавляет случайность для предотвращения thundering herd
- Retry только для retryable ошибок (TimeoutException, ConnectException)
- 4xx (Not Found, Bad Request) — retry бесполезен, сервер не починится
- maxAttempts обязателен — бесконечный retry = hang
- Fallback после исчерпания всех попыток
Частые уточняющие вопросы:
- Что такое thundering herd? Множество клиентов одновременно повторяют вызов — jitter «размазывает» повторы.
- Какие ошибки retryable? Timeout, connection refused, 5xx. НЕ retryable: 4xx, business exceptions.
- Exponential backoff формула? delay = baseDelay * multiplier^attempt, например 500ms, 1s, 2s, 4s.
- Spring Retry vs Resilience4j? Spring Retry проще, Resilience4j гибче (bulkhead, circuit breaker, time limiter).
Красные флаги (НЕ говорить):
- “Retry для всех ошибок” — нет, 404 retry бесполезен
- “Retry без лимита — надёжность” — нет, бесконечный retry = hang системы
- “Jitter не нужен, серверы справятся” — без jitter thundering herd
- “Retry = идемпотентность не важна” — критична, duplicate request возможен
Связанные темы:
- [[20. Что такое exponential backoff]]
- [[17. Как обеспечить отказоустойчивость микросервисов]]
- [[5. Что такое паттерн Circuit Breaker]]
- [[4. Что такое компенсирующие транзакции]]
- [[15. Как организовать коммуникацию между микросервисами]]