Files

3.5 KiB
Raw Permalink Blame History

Tasks: crawler-queue

1. Воркер (фаза 3)

  • 1.1 crawler/worker.py: claim_post (атомарный claim: classified=0 → -1, BEGIN IMMEDIATE) Проверка: in-memory тест — два вызова claim_post дают разные id (атомарно)
  • 1.2 process_post: classify_text + трафилатура для summary-only; UPDATE posts (direction/relevance/interest/summary/classified=1) Проверка: in-memory — пост «linux» → tech, classified=1; «игры» → games
  • 1.3 Исключение → classified=0 (вернуть в очередь) Проверка: try/except в work_loop, UPDATE classified=0; реализовано
  • 1.4 run(workers=8, limit=200): ThreadPoolExecutor, as_completed, счётчики (processed/classified/llm_ok) Проверка: python -m crawler.worker --workers 4 --limit 2 → 8 обработано; без ошибок

2. Сбор (фаза 1)

  • 2.1 crawler/crawl_sources.py: запуск telegram_crawler + rss_crawler (сбор новых кандидатов в очередь) Проверка: python -m crawler.crawl_sources --all → запускает оба; --crawler rss — только RSS

3. Страница /crawlers

  • 3.1 web/app.py: GET /crawlers (за auth) — таблица источников (slug, name, crawler, status, last_fetch, last_error, error_count, priority) + карточки очереди (pending/processing/done) Проверка: GET /crawlers с auth → 200, таблица с lwn (проверено httpx)
  • 3.2 web/templates/crawlers.html — шаблон (таблица + карточки + кнопки)
  • 3.3 POST /crawlers/run → запуск worker.run (фаза 3); POST /crawlers/reset → sources.status='alive', error_count=0 Проверка: POST /crawlers/run → воркер реально стартует (logs/worker.log), 200/302; reset — UPDATE

4. Интеграция и доки

  • 4.1 AGENT.MD — команды worker/crawl_sources (добавлены)
  • 4.2 STATUS.md / TODO.md — страница /crawlers, параллельная фаза 3 (обновлены)
  • 4.3 openspec validate crawler-queue → 0 ошибок
  • 4.4 TODO.md: задача «crawler-очередь» закрыта ✅

Примечания (найденные при реализации)

  • SQLite: соединение привязано к потоку — создаётся ВНУТРИ work_loop (нельзя делить между потоками).
  • Локальная Ollama (qwen3:8b) держит 1 слот — 8 параллельных LLM-запросов → таймауты (посты возвращаются в очередь, не теряются). Добавлен LLM_SEM (threading.BoundedSemaphore, MAX_CONCURRENT_LLM=2).
  • Очередь = posts (classified IS NULL OR 0) — отдельная таблица НЕ нужна (дублирование).
  • error_count/etag для RSS — из rss_state (в sources их нет); запрос /crawlers использует COALESCE.
  • SOURCE_RULES (classifier/keywords.py): правило источника с приоритетом над словарём и LLM. lwn → tech — все посты LWN (технологическое СМИ) получают направление tech детерминированно, без LLM (method='source-rule'). Работает в worker.py и старом CLI classifier.classify (оба JOIN sources → source_slug).