Retry, DLQ
Retry — повторить обработку сообщения при временном сбое, прежде чем сдаться. DLQ (Dead Letter Queue) — отдельный топик для сообщений, которые не удалось обработать даже после всех попыток — не теряются, а складываются туда для ручного разбора.
@RetryableTopic(
attempts = "3", // три попытки
backoff = @Backoff(delay = 1000, multiplier = 2), // экспоненциальная задержка между попытками
dltTopicSuffix = "-dlt" // суффикс топика для "мёртвых" сообщений
)
@KafkaListener(topics = "orders", groupId = "email-service")
void handleOrder(Order order) {
sendConfirmationEmail(order); // если упадёт — повторится автоматически
}
Если все 3 попытки провалились — сообщение автоматически уходит в топик orders-dlt, а не теряется бесследно.
Копнуть глубже
Зачем экспоненциальная задержка (multiplier), а не фиксированный интервал. Если внешний сервис (например, email-провайдер) временно перегружен, мгновенные повторные попытки усугубляют перегрузку. Экспоненциальная задержка (1с, 2с, 4с, 8с…) даёт сервису время восстановиться, прежде чем получит следующую попытку — снижает риск каскадной перегрузки.
DLQ требует ручного или автоматизированного разбора. Сообщения, попавшие в DLQ, не исчезают сами — нужен процесс мониторинга (алерт, если в DLQ появляются новые сообщения) и план, что с ними делать: исправить баг и переотправить вручную, или это сообщение действительно невалидное и его можно отбросить осознанно.
Не все ошибки стоит ретраить. Если сообщение само по себе некорректно (например, не парсится как JSON) — повторная попытка никогда не поможет, такую ошибку стоит сразу отправлять в DLQ, не тратя время на бессмысленные повторы. Retry имеет смысл для временных проблем (сеть, перегрузка внешнего сервиса), а не для постоянных ошибок в самих данных.
• почему экспоненциальная задержка лучше фиксированной и какие ошибки не стоит ретраить (если дошёл до 2-го слоя).