Files
vesti/openspec/changes/archive/2026-09-16-crawler-queue/proposal.md
T

46 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-краулер уже работает.