# 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-краулер уже работает.