Питання 19 · Розділ 17

Що таке патерн Retry і як його правильно використовувати

Structured Java interview answer with junior, middle, and senior-level explanation.

Мовні версії: English Russian Ukrainian

🟢 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

Типові помилки

  1. 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. Як організувати комунікацію між мікросервісами]]