Короткий ответ
Разделите загрузку, преобразование, проверки и отправку; задайте таймауты, ограниченные повторы с backoff и журналирование ошибок. Публикуйте отчёт только после проверок полноты и правдоподобия, а при провале отправляйте владельцу уведомление о сбое.
Как это работает подробнее
Повторяйте только временные ошибки сети и rate limit, а постоянные ошибки авторизации или схемы направляйте на разбор. Перед отправкой проверьте, что все источники завершились, ожидаемые периоды и аккаунты присутствуют, а контрольные суммы и диапазоны метрик допустимы. Сохраняйте статус запуска, чтобы повтор не отправлял дублирующий отчёт.
- Идемпотентность. Присваивайте запуску идентификатор периода, чтобы безопасно повторять сбойный этап без двойной публикации.
- Наблюдаемость. Логируйте длительность, число строк, ошибки и время последней успешной отправки.
Пример кода
validate_before_send.py
def validate_report(rows, expected_campaigns):
if not rows:
raise ValueError("Report is empty")
campaigns = {row["campaign_id"] for row in rows}
if not expected_campaigns.issubset(campaigns):
raise ValueError("Report is missing campaigns")
if any(row["spend"] < 0 for row in rows):
raise ValueError("Report contains negative spend")
return TrueЧто использовать на практике
- Безопасная отправка. Доставляйте отчёт после успешного завершения всех проверок и адресуйте отдельное уведомление владельцу при сбое.
- Восстановление. Храните временные результаты и ограничивайте повторы, чтобы не загружать API бесконечно.
Подводные камни
- Частичный успех. HTTP 200 от одного источника не означает, что выгрузка всех платформ полная.
- Повторы без фильтра. Повтор POST-запроса может создать дубликат сообщения; отделите безопасные чтения от отправки.