Короткий ответ
Нужно заранее решить и явно документировать стратегию для частичного отказа: либо вернуть частичный результат с явным указанием, какие данные недоступны, либо вернуть ошибку целиком — выбор зависит от того, критичны ли данные недоступного сервиса для корректности ответа.
Как это работает подробнее
при параллельном вызове нескольких внешних сервисов (например, через asyncio.gather с return_exceptions=True) можно получить смесь успешных результатов и исключений; дальше нужно решить для каждого источника данных, является ли он обязательным (и его отказ должен провалить весь запрос) или опциональным (и его отказ допускает деградацию функциональности).
Пример кода
example.py
import asyncio
async def get_order_summary(order_id: int) -> dict:
results = await asyncio.gather(
fetch_order_core(order_id), # критично: при отказе — ошибка всего запроса
fetch_recommendations(order_id), # некритично: при отказе — пропускаем блок
return_exceptions=True,
)
core, recommendations = results
if isinstance(core, Exception):
raise core # основные данные обязательны
response = {"order": core, "partial": False}
if isinstance(recommendations, Exception):
response["recommendations"] = None
response["partial"] = True
else:
response["recommendations"] = recommendations
return responseЧто использовать на практике
- Рекомендация. для некритичных дополнений (например, "рекомендованные товары" на странице заказа) разумно вернуть основной ответ без этого блока и залогировать/замониторить отказ; для критичных данных (например, актуальная цена перед оплатой) лучше вернуть ошибку, чем показать неполную или потенциально устаревшую информацию. Ответ должен явно сигнализировать клиенту о частичности данных (например, полем
partial: trueили списком недоступных источников), а не маскировать проблему.
Подводные камни
- Риски. возвращать частичный ответ без явного индикатора, что часть данных отсутствует из-за сбоя, из-за чего клиент/пользователь принимает неполные данные за полные; не задавать таймаут на каждый из параллельных вызовов, из-за чего медленный ответ одного сервиса задерживает весь агрегированный ответ вместо того, чтобы считаться отказом по таймауту.