[tradein][infra] Cron vs in-app scheduler — обсудить переход на Celery или native systemd timer #581

Closed
opened 2026-05-25 06:02:36 +00:00 by lekss361 · 3 comments
Owner

Контекст

Сейчас tradein-mvp использует in-app asyncio scheduler (services/scheduler.py, тикает в FastAPI lifespan). Простой, но:

  • Падает вместе с backend → нет catch-up.
  • Один tradein-backend процесс делает scraping + serves API → высокая нагрузка от scraping забивает API latency.
  • Невозможно scale horizontally (несколько backend → race condition в scrape_runs).

Альтернативы

A. Celery + Redis (как в main gendesign)

  • Pros: индустриальный стандарт, retry, beat, monitoring через Flower.
  • Cons: +2 контейнера (worker, beat), +Redis (если ещё нет в tradein стэке).

B. Forgejo Actions schedule

  • Pros: внешний trigger, видим в UI.
  • Cons: каждый run = container start (slow), нет shared state в памяти.

C. systemd timer на VPS

  • Pros: zero infra cost.
  • Cons: разнесено с docker, observability — отдельная история.

D. Status quo (in-app)

  • Pros: уже работает для avito_city_sweep.
  • Cons: всё перечисленное.

Acceptance

Решение зафиксировано как Decision в vault decisions/Decision_Tradein_Scheduler_Migration с PR roadmap.

Refs

  • sessions/Session_TradeIn_Dkp_Roadmap_May25 — "Celery autoload 2026Q2" outstanding
## Контекст Сейчас `tradein-mvp` использует **in-app asyncio scheduler** (`services/scheduler.py`, тикает в FastAPI lifespan). Простой, но: - ❌ Падает вместе с backend → нет catch-up. - ❌ Один tradein-backend процесс делает scraping + serves API → высокая нагрузка от scraping забивает API latency. - ❌ Невозможно scale horizontally (несколько backend → race condition в `scrape_runs`). ## Альтернативы ### A. Celery + Redis (как в main gendesign) - Pros: индустриальный стандарт, retry, beat, monitoring через Flower. - Cons: +2 контейнера (worker, beat), +Redis (если ещё нет в tradein стэке). ### B. Forgejo Actions schedule - Pros: внешний trigger, видим в UI. - Cons: каждый run = container start (slow), нет shared state в памяти. ### C. systemd timer на VPS - Pros: zero infra cost. - Cons: разнесено с docker, observability — отдельная история. ### D. Status quo (in-app) - Pros: уже работает для avito_city_sweep. - Cons: всё перечисленное. ## Acceptance Решение зафиксировано как Decision в vault `decisions/Decision_Tradein_Scheduler_Migration` с PR roadmap. ## Refs - `sessions/Session_TradeIn_Dkp_Roadmap_May25` — "Celery autoload 2026Q2" outstanding
lekss361 added the
automation
tradein
labels 2026-05-25 06:02:36 +00:00
lekss361 added the
needs-discussion
label 2026-05-30 15:03:11 +00:00
Author
Owner

+needs-discussion — decision-айтем (обсудить переход cron → Celery beat). Parked до решения по подходу; не actionable без выбора архитектуры. priority/low.

`+needs-discussion` — decision-айтем (обсудить переход cron → Celery beat). Parked до решения по подходу; не actionable без выбора архитектуры. priority/low.
lekss361 added this to the Praktika demo — Mon 2026-06-01 milestone 2026-05-30 17:21:13 +00:00
Collaborator

Операционные данные в дискуссию (2026-05-31, live-инциденты in-app scheduler)

Сегодняшние прогоны выявили конкретные минусы текущего in-app asyncio-scheduler:

  • Нет per-anchor/request watchdog → cian-city-sweep дважды завис на якоре (run #24 anchor 3, #29 anchor 1) — heartbeat замёрз, run не самозавершается (зомби-детект ловит только >6ч). Висящий HTTP без таймаута блокирует asyncio-задачу.
  • Один процесс scraping+API → тяжёлый sweep делит ресурсы с pilot-facing API.
  • Нет horizontal scale + shared-proxy coupling → два sweep'а (даже разных источников) делят один мобильный IP; same-source параллель (avito #26+#27) → бан обоих.

Рекомендация (независимо от Celery-решения): минимум добавить asyncio.wait_for(anchor, timeout=N) watchdog в run_*_city_sweep (дёшево, чинит зомби) — отдельная backend-задача. Полный Celery (вариант A) оправдан если scraping масштабируется, но +2 контейнера+Redis. Для демо status-quo+watchdog достаточно; Celery — post-demo.

## Операционные данные в дискуссию (2026-05-31, live-инциденты in-app scheduler) Сегодняшние прогоны выявили конкретные минусы текущего in-app asyncio-scheduler: - **Нет per-anchor/request watchdog** → cian-city-sweep дважды завис на якоре (run #24 anchor 3, #29 anchor 1) — heartbeat замёрз, run не самозавершается (зомби-детект ловит только >6ч). Висящий HTTP без таймаута блокирует asyncio-задачу. - **Один процесс scraping+API** → тяжёлый sweep делит ресурсы с pilot-facing API. - **Нет horizontal scale + shared-proxy coupling** → два sweep'а (даже разных источников) делят один мобильный IP; same-source параллель (avito #26+#27) → бан обоих. **Рекомендация (независимо от Celery-решения):** минимум добавить `asyncio.wait_for(anchor, timeout=N)` watchdog в `run_*_city_sweep` (дёшево, чинит зомби) — отдельная backend-задача. Полный Celery (вариант A) оправдан если scraping масштабируется, но +2 контейнера+Redis. Для демо status-quo+watchdog достаточно; Celery — post-demo.
Collaborator

Решение принято: Option C — systemd timer.

Анализ всех 4 вариантов относительно реального кода + demo deadline 2026-06-01:

Вариант Effort Новая инфра Риск
A. Celery + Redis L +2 контейнера 🔴
B. Forgejo Actions M нет 🟠
C. systemd timer S/M нет 🟢
D. Status quo нет 🟠 zombie runs

Redis в tradein-стеке не подключён → Celery требует добавки → рискованно к demo. systemd на VPS доступен сейчас.

PR roadmap (4 шага, ~1.5 дня):

  1. scripts/trigger-schedules.py — query scrape_schedules, POST /admin/scrape/{source}, flock lockfile
  2. systemd .service + .timer (60s) на VPS
  3. Deploy + smoke (scrape_runs растёт, нет дублей)
  4. SCHEDULER_ENABLE=false env flag — отключить in-app scheduler

ADR зафиксирован в vault: inbox/2026-05-31-1440-analyst-581-scheduler-decision.md (→ decisions/).

**Решение принято: Option C — systemd timer.** Анализ всех 4 вариантов относительно реального кода + demo deadline 2026-06-01: | Вариант | Effort | Новая инфра | Риск | |---|---|---|---| | A. Celery + Redis | L | +2 контейнера | 🔴 | | B. Forgejo Actions | M | нет | 🟠 | | **C. systemd timer** | **S/M** | **нет** | **🟢** | | D. Status quo | — | нет | 🟠 zombie runs | Redis в tradein-стеке не подключён → Celery требует добавки → рискованно к demo. systemd на VPS доступен сейчас. **PR roadmap (4 шага, ~1.5 дня):** 1. `scripts/trigger-schedules.py` — query scrape_schedules, POST /admin/scrape/{source}, flock lockfile 2. systemd `.service` + `.timer` (60s) на VPS 3. Deploy + smoke (scrape_runs растёт, нет дублей) 4. `SCHEDULER_ENABLE=false` env flag — отключить in-app scheduler ADR зафиксирован в vault: `inbox/2026-05-31-1440-analyst-581-scheduler-decision.md` (→ decisions/).
Sign in to join this conversation.
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#581
No description provided.