openspec: архив 14 завершённых change-ов (веб-фиксы, crawler-queue, own-content-hub, publisher-service); спеки влиты в openspec/specs

This commit is contained in:
kpa39l
2026-09-16 17:01:00 +00:00
parent 584582a48c
commit 771f6a8276
88 changed files with 1632 additions and 3 deletions
@@ -0,0 +1,46 @@
# Proposal: crawler-queue
## Why
Сейчас фазы сбора и обработки не разделены: каждый краулер (telegram/rss) сам
собирает посты и сам же (через `classifier.classify`) разбирает их на
классификацию. Это последовательно: весь прогон — один поток, один источник за
раз. При этом самая дорогая часть — фаза 3 (классификация через Ollama,
дотягивание текста трафилатурой) — выполняется последовательно и без видимости
процесса: непонятно, сколько кандидатов в очереди, какие источники живы, что
упало.
Пользователь хочет:
1. Отдельная страница `/crawlers` — статус работы краулеров (alive/dead,
last_fetch, ошибки) и размер очереди.
2. Двухфазный сбор: (1) краулеры проходят по источникам → ищут новых кандидатов;
(2) найденное кладётся в очередь; (3) воркеры разбирают очередь в НЕСКОЛЬКО
ПОТОКОВ.
Анализ текущего кода:
- Очередь фазы 2 уже существует — это `posts` со `status='new'` и
`classified IS NULL OR classified=0` (классификатор выбирает именно их,
`SELECT ... WHERE classified IS NULL OR classified=0 LIMIT ?`).
- Отдельная таблица `crawl_queue` НЕ нужна — она дублировала бы `posts`.
«Размер очереди» = `COUNT(*) FROM posts WHERE classified IS NULL OR classified=0`.
- Чего нет: (а) параллельной фазы 3 (ThreadPoolExecutor), (б) страницы `/crawlers`,
(в) разделения «сбор» и «обработка» как независимых запусков.
## Goal
- Параллельная фаза 3: воркеры (N потоков) разбирают очередь
`posts(classified=0)` — классификация (keywords → Ollama) + дотягивание текста
(trafilatura) по пайплайну `classifier.classify`.
- Страница `/crawlers` (веб, за auth): таблица источников (slug, name, crawler,
status, last_fetch, last_error, error_count, priority), размер очереди
(pending/processing/done), кнопки «Запустить сейчас» и «Сбросить dead».
- Разделение: `crawler/worker.py` (фаза 3, N потоков) и `crawler/crawl_sources.py`
(фаза 1: собрать новых кандидатов в очередь) — независимые запуски.
- Терминология (для доков): true-конкурентность на IO-bound задачах через потоки;
GIL не мешает, т.к. фаза 3 — ожидание сети.
## Non-goals
- Не вводим Redis/RabbitMQ/брокеры — SQLite-очередь (claim по `posts`) достаточна.
- Не выносим в микросервисы — всё в рамках существующего веба/краулера.
- Не переписываем telegram_crawler; RSS-краулер уже работает.