feat: expand platform APIs, sources, and test coverage
Some checks failed
CI/CD Pipeline / Run Tests (pull_request) Successful in 1m53s
CI/CD Pipeline / Telegram Notify Success (push) Has been cancelled
CI/CD Pipeline / Run Tests (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (pull_request) Failing after 2m54s
CI/CD Pipeline / Telegram Notify Success (pull_request) Has been skipped

This commit is contained in:
2026-03-17 12:56:48 +01:00
parent b505c67968
commit 3d298ce352
101 changed files with 8387 additions and 292 deletions

View File

@@ -0,0 +1,128 @@
# ADR-011: Idempotency and Retry Strategy for Background Tasks
## Status
Accepted
## Context
Система активно использует фоновые задачи Celery для:
- загрузки данных из внешних источников
- инкрементальной синхронизации
- обработки файлов
- периодических сканирований и парсинга
Внешние источники и фоновые очереди не гарантируют:
- exactly-once delivery
- стабильность сети
- неизменность ответа источника
- отсутствие повторных запусков задач
- отсутствие ручных перезапусков оператором
Также возможны следующие сценарии:
- worker завершился после частичной записи данных
- задача была запущена повторно по retry
- beat и ручной запуск вызвали одинаковую задачу почти одновременно
- внешняя система ответила ошибкой после того, как часть данных уже была получена
- оператор повторно инициировал синхронизацию за тот же период
Для такого класса системы идемпотентность является не оптимизацией, а обязательным архитектурным требованием.
## Decision
Все фоновые задачи, изменяющие данные или взаимодействующие с нестабильными внешними источниками, должны проектироваться как idempotent-first.
### Основные правила
1. Повторный запуск одной и той же задачи не должен приводить к неконтролируемому дублированию данных.
2. Результат повторного выполнения должен быть либо:
- идентичен первому успешному выполнению,
- либо безопасно приводить систему к тому же целевому состоянию.
3. Retry рассматривается как нормальный сценарий эксплуатации, а не как исключение.
### Идемпотентность обеспечивается за счет
- уникальных ограничений на уровне БД для естественных бизнес-ключей
- upsert/update-or-create подходов там, где это возможно
- явной привязки загружаемых данных к периоду, источнику, типу выгрузки или внешнему идентификатору
- дедупликации на уровне сервисного слоя перед записью
- разделения этапов extract / transform / load
- фиксации статуса фоновой задачи и контекста её выполнения
- запрета на "append-only" запись без проверки уникальности для синхронизируемых сущностей
### Retry policy
Retry допускается только для временных ошибок:
- сетевые сбои
- временная недоступность внешнего источника
- rate limiting
- временные ошибки брокера или инфраструктуры
- временные проблемы с файловой системой или внешним сервисом
Retry не должен безусловно выполняться для:
- ошибок валидации входных данных
- ошибок схемы/контракта источника
- систематических ошибок парсинга
- нарушений инвариантов модели
- ошибок конфигурации
Для retry необходимо:
- использовать ограниченное число повторов
- использовать backoff
- логировать причину повтора
- сохранять контекст периода/источника/операции
### Concurrency policy
Для задач, работающих по одному и тому же периоду или источнику, должна применяться логическая защита от параллельного конкурентного запуска.
Предпочтительный порядок контроля:
1. блокировка на уровне бизнес-контракта задачи
2. проверка существующего job-run статуса
3. защита уникальными ограничениями БД
4. безопасное повторное выполнение как fallback
### Operational policy
Задача считается корректной, если после:
- retry
- повторного ручного запуска
- запуска за уже обработанный период
- частичного падения и повторного восстановления
данные остаются консистентными и не требуют ручной чистки в обычном сценарии эксплуатации.
## Consequences
### Positive
- система устойчива к повторным запускам и временным отказам
- снижается риск дублирования данных
- упрощается эксплуатация и ручной re-run задач
- Celery retry становится безопасным штатным механизмом
- упрощается восстановление после сбоев worker-процессов
### Negative
- усложняется реализация сервисного слоя и моделей
- требуется дисциплина в проектировании бизнес-ключей
- часть задач становится медленнее из-за дополнительных проверок
- нужны дополнительные ограничения и индексы в БД
- необходимо явно проектировать поведение при partial success
## Alternatives considered
### 1. At-most-once execution
Отклонено, так как не соответствует реальной природе фоновой обработки и нестабильных внешних интеграций.
### 2. Полагаться только на Celery retry без идемпотентности на уровне домена
Отклонено, так как это приводит к дублированию данных и хрупкому поведению при сбоях.
### 3. Полная ручная очистка данных перед каждым повторным запуском
Отклонено, так как не масштабируется и опасно в эксплуатации.
## Notes
Следующими связанными решениями должны быть:
- политика дедупликации данных
- модель частичной загрузки и фиксации прогресса
- политика конкурентного запуска задач