Как сетевая ошибка REST-запроса влияет на уведомление второго сервиса
Что проверяют
Понимаете ли вы, что сетевая ошибка не говорит, дошло ли уведомление. И умеете ли спроектировать доставку так, чтобы второй сервис не остался без события и не получил его дважды. Следом спрашивают про outbox и идемпотентность.
Как отвечать
Начните с неоднозначности. Сервис A сохранил заказ и шлёт POST в сервис B. Если пришёл HttpRequestException или TaskCanceledException по таймауту (у HttpClient.Timeout по умолчанию 100 секунд), возможны три исхода: запрос не дошёл, дошёл и не обработан, обработан, но потерялся ответ. Снаружи их не различить, поэтому любое решение строится на повторах и защите от дублей.
Каркас ответа:
- повторы:
HttpClientчерезIHttpClientFactory, политика ретраев с экспоненциальной задержкой и джиттером. Сейчас это Polly v8 или пакетMicrosoft.Extensions.Http.ResilienceсAddStandardResilienceHandler(), где сразу собраны ретраи, таймауты и circuit breaker; - идемпотентность: у события есть стабильный идентификатор, он уходит в заголовке вроде
Idempotency-Key, и сервис B отбрасывает повтор, который уже обработал; - двойная запись: коммит в базу A и HTTP-вызов в B не атомарны. Упал процесс между ними, и событие потеряно навсегда. Решение Transactional Outbox: событие пишется в таблицу outbox той же транзакцией, что и заказ, а
BackgroundServiceотправляет его с повторами и помечает доставленным. Готовые реализации есть в MassTransit и NServiceBus; - брокер вместо прямого вызова: если B должен узнать о событии, а не ответить синхронно, надёжнее публикация в RabbitMQ или Kafka, тоже через outbox.
Итог: доставка «хотя бы один раз» плюс идемпотентный получатель дают эффект «ровно один раз».
Где спотыкаются
Считают таймаут отказом. Сервис A откатывает заказ, а сервис B уже отправил клиенту письмо о нём.
Вызывают B внутри транзакции базы. Блокировки держатся всё время сетевого запроса, а откат после успешного вызова оставляет B с событием, которого не было.
Ловят исключение и только пишут в лог. Без повторной отправки уведомление теряется, и расхождение всплывает через недели.