Introduce a deployment recording system to track dashboard versions across environments and improve the Git management user experience. - Add `Deployment` model and Alembic migration to persist deployment history. - Implement `GitDeploymentRecorder` and `GitFingerprint` plugins to automate deployment logging and content hashing. - Add `get_deployment_status` API endpoint to retrieve real-time environment states. - Refactor `GitLifecycleHeader` to prioritize Call-to-Action (CTA) buttons and improve visual hierarchy. - Update `GitWorkspacePanel` to emphasize version saving and streamline commit workflows. - Enhance `GitEnvironmentTimeline` with deployment status integration, collapsible UI, and improved theme consistency. - Add auto-navigation logic in `GitManagerModel` to guide users to relevant tabs based on recommended actions. - Clean up obsolete documentation and update i18n strings for git visualization features.
211 lines
17 KiB
Markdown
211 lines
17 KiB
Markdown
# Ортогональное сравнение: Наш Scheduler + Worker vs Celery и открытые альтернативы
|
||
|
||
**Дата**: 2026-07-10
|
||
**Контекст проекта**: superset-tools (FastAPI + Svelte).
|
||
**Наша реализация**: APScheduler (in-process) + кастомный in-process `TaskManager`/`JobLifecycle`.
|
||
|
||
## Краткое резюме (TL;DR)
|
||
|
||
| Система | Архитектура | Брокер | Распределённость | Интерактивные задачи (AWAITING_*) | Реал-тайм UI/логи | Операционная сложность | Лучше всего для |
|
||
|----------------------|------------------------------|--------|------------------|-----------------------------------|-------------------|------------------------|-----------------|
|
||
| **Наш (APScheduler + TaskManager)** | In-process (один backend) | Нет | Только вертикальная | **Отличная** (встроенные) | **Отличная** (WS + Task Center) | **Низкая** | Admin tools, интерактивные фоновые задачи, LLM/backup/migration внутри одного приложения |
|
||
| **Celery + Beat** | Producer + Broker + Workers (отдельные процессы) | Обязателен (Redis/Rabbit/...) | **Отличная** | Сложно (требует кастомизации) | Средняя (Flower + кастом) | Высокая | Высоконагруженные распределённые пайплайны, CPU-bound, высокая отказоустойчивость |
|
||
| **APScheduler (standalone)** | In-process (или с jobstores) | Нет | Ограниченная | Через кастом | Кастом | Низкая | Простые cron-задачи внутри приложения |
|
||
| **Huey** | Лёгкий (Redis/SQLite) | Опционально | Хорошая | Нет | Кастом | Низкая-средняя | Маленькие/средние приложения |
|
||
| **RQ** | Простой Redis | Redis | Хорошая | Нет | Кастом | Низкая | Простые очереди |
|
||
| **Dramatiq** | Современный (Redis/Rabbit) | Обязателен | Хорошая | Нет | Кастом | Средняя | Более простая/надёжная замена Celery |
|
||
| **ARQ / Taskiq** | Async-native (Redis-first) | Redis | Хорошая | Ограничено | Кастом | Средняя | FastAPI + высококонкурентные I/O-задачи |
|
||
| **Procrastinate** | Postgres-native | Нет (Postgres) | Хорошая | Ограничено | Кастом | Средняя | Когда не хочется дополнительный брокер |
|
||
|
||
**Наш главный выигрыш**: глубокая интеграция с UI, человеческие состояния задач (`AWAITING_INPUT`, `AWAITING_MAPPING`), real-time логи через WebSocket и нулевая дополнительная инфраструктура.
|
||
|
||
**Главный проигрыш**: нет горизонтального масштабирования и автоматической отказоустойчивости при падении процесса.
|
||
|
||
## Что такое "наш" scheduler и worker (точные факты из кода)
|
||
|
||
### Scheduler
|
||
- Файл: `backend/src/core/scheduler.py`
|
||
- `SchedulerService` оборачивает `BackgroundScheduler` (APScheduler 3.11).
|
||
- Загрузка: `load_schedules()` очищает все jobs и пересоздаёт из:
|
||
- Backup schedules — из `config.environments[].backup_schedule`.
|
||
- Translation schedules — из таблицы `TranslationSchedule` (is_active).
|
||
- Validation policies — динамический cron + `ThrottledSchedulerConfigurator` (распределение задач внутри окна).
|
||
- Триггеры: `CronTrigger.from_crontab(...)` + timezone.
|
||
- Мост: `AsyncJobRunner` (отдельный файл) — `run_coroutine_threadsafe` + `call_later` для delayed execution.
|
||
- Нет `SQLAlchemyJobStore` / persistent jobstore — расписания восстанавливаются из прикладных таблиц и конфига при старте.
|
||
|
||
### Worker / Task Execution
|
||
- `TaskManager` (фасад) + `JobLifecycle` + `TaskGraph` + `EventBus`.
|
||
- Создание: `create_task` → `asyncio.create_task(_run_task)`.
|
||
- Выполнение: `plugin.execute(...)` (async или `asyncio.to_thread`).
|
||
- Ограничение блокирующих операций: именованные `ThreadPoolExecutor` (db/file/git) — `core/utils/executors.py` (ADR-0011).
|
||
- Состояния: `PENDING → RUNNING → SUCCESS/FAILED` + `AWAITING_MAPPING` / `AWAITING_INPUT`.
|
||
- Персистентность: отдельная таблица `task_records` + `task_logs` (может быть `TASKS_DATABASE_URL` = основной или sqlite).
|
||
- Реал-тайм: `EventBus` (asyncio.Queue) → WS для логов, статуса, событий датасетов.
|
||
- Интерактивность: `resume_task_with_password`, `resolve_task` — задачи реально "парятся" и ждут пользователя.
|
||
- Деплой: **один контейнер `backend`** (docker-compose.yml). Нет отдельного worker-сервиса.
|
||
|
||
**ADR-0011** явно отвергает multiprocessing workers и брокер в пользу async + bounded executors внутри процесса.
|
||
|
||
## Ортогональные проекции (13 измерений)
|
||
|
||
### 1. Architecture & Deployment Model
|
||
**Наш**: Монолитный процесс (API + scheduler + executor).
|
||
**Celery**: Три отдельных роли (app, beat, worker(s)) + брокер.
|
||
**ARQ/Taskiq**: Async workers как отдельные процессы/контейнеры.
|
||
**Huey/RQ**: Лёгкие отдельные worker-процессы.
|
||
**APScheduler standalone**: Обычно в том же процессе, что и приложение.
|
||
|
||
**Вывод**: Наш — самый простой в деплое (один сервис).
|
||
|
||
### 2. External Dependencies & Operational Surface
|
||
**Наш**: Только основная БД (опционально отдельная для задач). APScheduler — чисто in-memory.
|
||
**Celery**: Брокер + результат + мониторинг (Flower) + beat.
|
||
**Dramatiq/ARQ**: Брокер обязателен.
|
||
**Procrastinate**: Только Postgres.
|
||
|
||
**Наш выигрывает** по операционной простоте.
|
||
|
||
### 3. Scheduling (Cron + Dynamic jobs)
|
||
**Наш**: Полноценный Cron + динамическое добавление/удаление/перезагрузка из нескольких источников. Throttling внутри окон.
|
||
**Celery Beat**: Cron/interval + `django-celery-beat` для динамики.
|
||
**APScheduler**: Лучший в классе триггеров (date/interval/cron) + jobstores.
|
||
**Huey**: Periodic tasks через `huey.contrib`.
|
||
**RQ**: Нет встроенного — внешний планировщик или rq-scheduler.
|
||
|
||
**Наш**: Очень удобен для пользовательских расписаний (translate, validation, backup).
|
||
|
||
### 4. Task Execution Model & Concurrency
|
||
**Наш**: asyncio + bounded thread pools внутри event loop. Плагины выполняются в контексте приложения.
|
||
**Celery**: Отдельные процессы (prefork/eventlet/gevent).
|
||
**ARQ/Taskiq**: Нативный asyncio в worker'ах.
|
||
**Dramatiq**: Sync-first (можно с gevent).
|
||
|
||
Для I/O-heavy (LLM, HTTP к Superset, Git) async-модели (наш + ARQ) эффективнее по вертикали.
|
||
|
||
### 5. Scalability & Distribution
|
||
**Наш**: Только вертикальная (добавить CPU/RAM одной ноде). При нескольких backend'ах — дублирование расписаний.
|
||
**Celery / большинство очередей**: Линейное горизонтальное масштабирование (добавляй workers).
|
||
**APScheduler с RedisJobStore**: Ограниченная распределённость.
|
||
|
||
**Наш** не предназначен для десятков тысяч задач в минуту.
|
||
|
||
### 6. Reliability, Resilience & Fault Tolerance
|
||
**Наш**:
|
||
- Расписания восстанавливаются при рестарте.
|
||
- Задачи сохраняют состояние.
|
||
- **Проблема**: RUNNING задачи при падении процесса не возобновляются автоматически. AWAITING_* требуют ручного рестарта.
|
||
- Нет встроенных ретраев на уровне очереди.
|
||
|
||
**Celery**: Ack, redeliver, retries, max_retries, dead-letter, result backend.
|
||
**Dramatiq**: Хорошие ретраи по умолчанию.
|
||
**Procrastinate**: Надёжность Postgres.
|
||
|
||
**Критично для нас**: если задача "перевода 200k строк" упала вместе с backend — нужно перезапускать вручную.
|
||
|
||
### 7. Task Lifecycle Richness & Advanced Features
|
||
**Наш** — лидер в своей нише:
|
||
- AWAITING_INPUT (пароли БД)
|
||
- AWAITING_MAPPING (разрешение ресурсов)
|
||
- TaskContext для structured logging
|
||
- Отмена, resume, resolve через API
|
||
|
||
**Celery**: canvas (chain/group/chord), routing, priority, eta/countdown, rate_limit, task_revocation.
|
||
Остальные: базовые retry + простые очереди. Интерактивность почти ни у кого нет "из коробки".
|
||
|
||
**Это одно из самых сильных конкурентных преимуществ** нашего решения для инструмента администратора.
|
||
|
||
### 8. Observability, Monitoring & UX Integration
|
||
**Наш**:
|
||
- Нативный Task Status Center (spec 034)
|
||
- WebSocket real-time логи + статус
|
||
- Фильтры, summary, drawer с логами
|
||
- RBAC на уровне задач
|
||
|
||
**Celery**: Flower (отдельное приложение), Prometheus экспортеры, кастом.
|
||
Другие: обычно только логи + кастомный дашборд.
|
||
|
||
**Наш** выигрывает для пользователей продукта (не только DevOps).
|
||
|
||
### 9. Persistence (Schedules + Task State/Results/Logs)
|
||
**Наш**:
|
||
- Расписания — в прикладных таблицах + config.
|
||
- Задачи/логи — `task_records` / `task_logs` (JSON + отдельная таблица логов).
|
||
- Высокопроизводительная батчевая запись логов.
|
||
|
||
**Celery**: Результаты в отдельном backend (Redis/Postgres/…). Задачи обычно не хранят детальные логи внутри.
|
||
**APScheduler + SQLAlchemyJobStore**: Полная персистентность расписаний.
|
||
**Huey**: Опционально SQLite/Redis.
|
||
|
||
### 10. Resource Footprint, Isolation & Performance Profile
|
||
**Наш**: Низкий overhead. Всё в одном процессе. Bounded pools дают backpressure.
|
||
**Celery prefork**: Выше потребление памяти, хорошая изоляция.
|
||
**Async workers (ARQ)**: Отличная плотность I/O-задач на ядро.
|
||
**CPU-bound задачи**: Процессные модели лучше (изоляция GIL).
|
||
|
||
Для наших задач (LLM, Superset API, Git, batch SQL) in-process async + pools работает отлично.
|
||
|
||
### 11. Ease of Development, Testing & Integration (FastAPI)
|
||
**Наш**: Плагины просто реализуют `execute`. Всё в одном codebase. Легко тестировать с TaskContext.
|
||
**Celery**: Отдельный app, сериализация, импорт проблем, тесты сложнее.
|
||
**ARQ/Taskiq**: Хорошая интеграция с FastAPI (async-native).
|
||
**APScheduler**: Самый простой для простых cron.
|
||
|
||
### 12. Ecosystem, Maturity & Maintenance Burden
|
||
- **Celery**: Самая зрелая, огромная экосистема, но репутация "сложная и полна сюрпризов".
|
||
- **APScheduler**: Зрелая, активно поддерживается.
|
||
- **Dramatiq**: Создавалась как "лучше Celery".
|
||
- **ARQ**: От автора Pydantic/FastAPI — отличный современный выбор.
|
||
- **Huey/RQ**: Простые, меньше "магии".
|
||
|
||
Наш — полностью кастомный слой поверх APScheduler. Поддержка ложится на команду проекта.
|
||
|
||
### 13. Best-fit Use Cases & Trade-off Summary
|
||
**Идеально для нас сегодня**:
|
||
- Инструмент администратора Superset.
|
||
- Задачи с человеческим участием.
|
||
- Реал-тайм обратная связь важнее горизонтального масштаба.
|
||
- Минимальная операционная нагрузка.
|
||
|
||
**Когда стоит рассмотреть Celery/ARQ/Dramatiq**:
|
||
- Появятся десятки тысяч фоновых задач.
|
||
- Нужна настоящая отказоустойчивость (задача должна дожить до выполнения даже при рестарте всего кластера).
|
||
- CPU-heavy работа (большие вычисления, не I/O).
|
||
- Несколько независимых сервисов, которые должны шарить очередь.
|
||
|
||
**Гибрид возможен**: оставить текущий механизм для UI-driven и scheduled admin-задач, а тяжёлые batch-операции вынести в отдельную очередь.
|
||
|
||
## Сравнительная матрица (сводка)
|
||
|
||
(См. TL;DR таблицу выше + детальные проекции.)
|
||
|
||
## Рекомендация для superset-tools
|
||
|
||
**Оставить текущую архитектуру как основную.**
|
||
|
||
Причины:
|
||
- Отлично соответствует текущим потребностям (переводы, бэкапы, валидации, миграции, git).
|
||
- Уникальные фичи (AWAITING_*, TaskContext, нативный красивый Task Center) очень ценны для пользователей.
|
||
- Низкая операционная сложность — большое преимущество.
|
||
- ADR-0011 и вся эволюция проекта сознательно шли в эту сторону.
|
||
|
||
**Что можно улучшить без революции** (опционально):
|
||
- Добавить `SQLAlchemyJobStore` или RedisJobStore для расписаний (защита от потери при странных рестартах).
|
||
- Добавить автоматический "reconcile" для зависших RUNNING задач при старте (по таймауту или heartbeat).
|
||
- Для очень тяжёлых переводов — рассмотреть возможность выноса в отдельный worker позже.
|
||
|
||
**Не переходить на Celery "на всякий случай"** — это добавит значительную сложность без немедленной пользы.
|
||
|
||
## Источники
|
||
|
||
- Код проекта: `backend/src/core/scheduler.py`, `task_manager/*`, `ADR-0011-async-backend.md`, docker-compose.
|
||
- Внешние сравнения:
|
||
- APScheduler vs Celery Beat (leapcell.io, 2025) [web:3].
|
||
- Reddit 2026: "Choosing a Python task queue library".
|
||
- Dramatiq motivation page.
|
||
- ARQ adoption stories и бенчмарки (см. также [web:0], [web:9]).
|
||
- StackShare / официальная документация.
|
||
|
||
---
|
||
|
||
*Сравнение выполнено ортогонально — по независимым измерениям, без навязывания одного "лучшего" решения.* |