Когда использовать механизм автореплея при ошибках в сервисах
Что проверяют
Умеете ли вы как аналитик описать повтор так, чтобы разработчик не превратил его в источник дублей и лавины запросов. Следом обычно спрашивают, как гарантировать, что повтор платежа или заказа не спишет деньги дважды.
Как отвечать
Ответ удобно строить как требования, которые вы запишете в спецификацию интеграции:
- какие ошибки повторять: только временные. Таймаут, обрыв соединения,
502,503,504,429с учётомRetry-After. Ответы400,401,403,404,422повторять бессмысленно, результат будет тем же; - идемпотентность:
GET,PUT,DELETEпо контракту идемпотентны,POSTнет. Для создания сущностей нужен ключ идемпотентности: клиент генерирует его один раз и шлёт во всех попытках, а сервер по нему возвращает уже созданный результат; - сколько и как часто: число попыток, экспоненциальная задержка со случайным разбросом (jitter) и общий дедлайн, после которого операция считается проваленной;
- что после исчерпания попыток: сообщение уходит в очередь недоставленных (dead letter в RabbitMQ, отдельный топик в Kafka), по нему срабатывает алерт и описан ручной разбор;
- защита зависимого сервиса: circuit breaker, который после серии отказов на время перестаёт слать запросы.
Для асинхронного обмена добавьте, что брокер даёт доставку «хотя бы один раз», значит потребитель обязан отбрасывать дубли по идентификатору сообщения. Если сервис пишет в базу и публикует событие, упомяните transactional outbox.
Где спотыкаются
Приводят пример «перевод денег идемпотентен». Как раз нет: без ключа идемпотентности повтор после таймаута спишет сумму второй раз, ведь первый запрос мог дойти.
Забывают про усиление повторов по цепочке. Три попытки на каждом из трёх уровней дают до 27 запросов в нижний сервис именно тогда, когда он и так перегружен. Повторять стоит на одном уровне.
Задают только число попыток без задержки и разброса. Сотня клиентов, повторяющих ровно через секунду, добивает восстанавливающийся сервис синхронной волной.