Skip to content

Раздел 2: Telegram-бот и планировщик

Проект: ADOLF — AI-Driven Operations Layer Framework
Модуль: Watcher / Bot & Scheduler
Версия: 4.0
Дата: Февраль 2026


2.1 Обзор

Telegram-бот (bot.js) — точка входа и основной интерфейс управления подсистемой Collector. Процесс bot.js объединяет в себе четыре функциональных модуля:

МодульФайлРоль
Telegram Botbot.jsПриём команд, отправка отчётов и алертов
Schedulerscheduler.jsЦиклические задачи: расписания, очередь, мониторинг
Orchestratororchestrator.jsВыбор ПК для задач (описан в Разделе 3)
Runnerrunner.jsЗапуск сканеров/обогатителей (описан в Разделе 3)

Запуск: node bot.js (systemd: watcher-bot.service).

Конфигурация

Переменные окружения (.env):

ПеременнаяОписание
BOT_TOKENТокен Telegram-бота (обязательно)
ADMIN_CHAT_IDID чата администратора (обязательно)

Доступ к боту ограничен проверкой msg.chat.id === ADMIN_CHAT_ID на каждую команду.

Инициализация при запуске

При старте bot.js выполняет последовательность:

Очистка зависших сканов гарантирует, что задачи, прерванные аварийным рестартом, не блокируют очередь. Они помечаются как failed с пометкой Orphaned (bot restart).


2.2 Команды бота

Быстрый скан

Самый частый сценарий — отправка ID продавца с префиксом маркетплейса.

ВводМаркетплейсПример
WB<id>WildberriesWB1025130
OZ<id> или OZON<id>OzonOZ465656
YM<id>Яндекс.МаркетYM213246
Голое числоВыбор кнопками1025130

Быстрый скан автоматически создаёт продавца в БД (если не существует) с именем PREFIX-ID и приоритетом normal. Если на диске есть незавершённый файл results_seller_<id>.json, сканер продолжит сбор с последней точки.

Управление продавцами

КомандаСинтаксисОписание
/add/add <mp> <id> "<имя>" [приоритет]Добавить продавца. mp: wb, oz, ym. Приоритет: low, normal, high, critical
/list/listСписок всех продавцов с приоритетами, расписаниями и датой последнего скана
/remove/remove <id>Пометить продавца как removed (мягкое удаление)
/pause/pause <id>Приостановить сканирование продавца
/resume/resume <id>Возобновить сканирование
/priority/priority <id> <уровень>Изменить приоритет (low, normal, high, critical)
/schedule/schedule <id> <часы>Изменить интервал сканирования (в часах)
/autoenrich/autoenrich <id> [часы]Настроить автообогащение. 0 = отключить, по умолчанию 24ч

Пример добавления продавца:

/add wb 1025130 "Конкурент А" high

Ответ:

✅ Добавлен:
• Конкурент А (wildberries)
• ID: 1025130
• Приоритет: high

Управление задачами

КомандаСинтаксисОписание
/scan/scan <id>Ручной запуск сканирования. Если нет свободных ПК — задача попадает в очередь
/enrich/enrich <id>Ручной запуск обогащения. Требует предварительного скана
/newscan/newscan <id>Удалить прогресс предыдущего скана и начать заново
/queue/queueТекущая очередь и выполняемые задачи
/running/runningАктивные задачи с временем выполнения и портами ПК
/history/history [N]История последних N сканов (по умолчанию 10)
/retry/retryПереставить все упавшие задачи в очередь

Результаты

КомандаСинтаксисОписание
/result/result <id>Краткий отчёт последнего скана: товаров, диапазон цен, рейтинг, время
/diff/diff <id>Сравнение двух последних сканов: новые, исчезнувшие, изменения цен
/file/file <id>Скачать JSON-файл последнего скана (results_seller_<id>.json)

Инфраструктура

КомандаСинтаксисОписание
/status/statusОбщий статус: ПК (online/offline/busy/free), продавцов, очередь, выполнено, ошибки
/pc/pcДетали каждого ПК: имя, порт, браузер, ОС, задач выполнено, время последнего ответа
/screenshot/screenshotСкриншот текущей страницы первого доступного ПК
/summary/summaryРучной вызов утренней сводки

Главное меню (/start, /help)

Команда /start или /help отображает справку и inline-клавиатуру для быстрого доступа:

┌─────────────────────────────────────────┐
│  📊 Статус  │  🖥️ ПК   │  📷 Скриншот │
├─────────────────────────────────────────┤
│  📋 Продавцы │  ⏳ Очередь │  📜 История │
├─────────────────────────────────────────┤
│  🔄 Повторить упавшие  │  📊 Сводка   │
└─────────────────────────────────────────┘

Нажатие кнопки генерирует синтетическое сообщение с соответствующей командой (/status, /pc, /screenshot, /list, /queue, /history, /retry, /summary), которое обрабатывается стандартными обработчиками.


2.3 Поведение уведомлений

Отправка результатов в Telegram

СобытиеТекстовый отчётJSON-файл
Завершение скана (ручной или автоматический)
Ручной /enrich
Автообогащение (по расписанию)
Ошибка задачи✅ (с описанием ошибки)

Принцип: JSON-файлы отправляются только при ручном запуске обогащения. Все остальные данные хранятся на диске и доступны через REST API.

Формат отчёта о скане

✅ Сканирование завершено

Продавец: Конкурент А
Маркетплейс: Wildberries
ID: 1025130
Товаров найдено: 142
Диапазон цен: 590 – 8 900₽
Средний рейтинг: 4.6
Время сканирования: 95 мин
Браузер: moscow-ivan

Алерты мониторинга ПК

СобытиеСообщение
ПК подключился🟢 ПК подключился: moscow-ivan (порт 9301) + версия Chrome
ПК отключился🔴 ПК отключился: moscow-ivan (порт 9301)
Первый запуск (ПК уже online)🟢 ПК онлайн: moscow-ivan (порт 9301)

Мониторинг сравнивает текущее состояние каждого ПК с предыдущим (previousPcStates). Алерты отправляются только при смене состояния. Первый опрос после старта бота сообщает обо всех найденных ПК как онлайн.


2.4 Планировщик (scheduler.js)

Архитектура

Scheduler запускается вызовом scheduler.start() из bot.js при инициализации. Все циклы работают на setInterval внутри единого процесса Node.js.

Цикл 1: checkSchedules — расписания сканов

Интервал: scheduler.scheduleCheckIntervalMs (по умолчанию 5 мин).

Логика: перебирает всех активных продавцов, проверяет next_scan_at. Если время наступило и нет активной/ожидающей задачи для данного продавца — создаёт запись в scans со статусом queued.

Цикл 2: checkEnrichSchedules — расписания обогащения

Интервал: scheduler.enrichCheckIntervalMs (по умолчанию 5 мин).

Аналогичен циклу 1, но проверяет next_enrich_at и создаёт задачи с task_type = 'enrich', source = 'auto'. Дополнительно проверяет наличие файла скана на диске — без него обогатитель не сможет работать.

Цикл 3: tryRunNext — запуск из очереди

Интервал: scheduler.tryRunNextIntervalMs (по умолчанию 30 сек).

Основной цикл диспетчеризации. Обрабатывает два типа задач.

Scan-задачи (требуют ПК):

  1. Получить список queued scan-задач из БД
  2. Запросить количество свободных ПК через CDP Pool (/summary)
  3. Для каждой задачи (до количества свободных ПК): вызвать orchestrator.choosePC()runner.runScan()
  4. Задержка 500 мс между запусками (чтобы /acquire успел пометить ПК как busy)

Enrich-задачи (WB без CDP, Ozon/YM — с CDP):

  1. Проверить лимит параллельного обогащения (scheduler.enrichLimit, по умолчанию 2)
  2. Для CDP-маркетплейсов: запросить ПК через оркестратор
  3. Для WB (HTTP only): запуск без выделения ПК
  4. Файл отправляется в Telegram только при source = 'manual'

Цикл 4: monitorBrowser — мониторинг ПК

Интервал: scheduler.monitorIntervalMs (по умолчанию 15 сек).

Запрашивает /status у CDP Pool и сравнивает с предыдущим состоянием каждого ПК. Отправляет алерты при изменении: подключение, отключение, удаление из пула.

Хранение состояния — in-memory объект previousPcStates: { name: { alive, browser } }. Не персистентный — при рестарте бота первый опрос сообщает обо всех найденных ПК как «онлайн».

Цикл 5: rotateFiles — ротация файлов

Интервал: scheduler.rotationIntervalMs (по умолчанию 24 часа).

Удаляет старые файлы результатов по двум директориям:

ДиректорияПараметр лимитаПо умолчанию
results/catalog/scheduler.catalogKeepPerSeller10 файлов
results/enriched/scheduler.enrichedKeepPerSeller30 файлов

Логика ротации: файлы группируются по ключу {mp}_seller_{id}, сортируются по дате (из имени файла), самые старые сверх лимита удаляются.

Цикл 6: morningSummary — утренняя сводка

Проверка: каждую минуту, срабатывает при совпадении UTC-часа и минуты с параметрами scheduler.morningSummaryUtcHour и scheduler.morningSummaryUtcMinute (по умолчанию 05:00 UTC = 08:00 MSK).

Формат сводки:

📊 Утренняя сводка

ПК: 🟢 moscow-ivan, moscow-anna
Продавцов: 12
В очереди: 3
Выполняется: 1
Завершено: 287
Ошибок: 2

Последние сканы:
✅ Конкурент А — 142 шт.
✅ Конкурент Б — 89 шт.
❌ Конкурент В — 0 шт.

2.5 Параметры конфигурации планировщика

Все параметры управляются через config.json (модуль config.js).

Параметры с hot-reload

Изменения применяются мгновенно (через fs.watchFile), без перезапуска сервиса.

ПараметрПо умолчаниюМинМаксОписание
scheduler.defaultScanScheduleHours721720Интервал сканирования для новых продавцов (часы)
scheduler.defaultEnrichScheduleHours241720Интервал обогащения для новых продавцов (часы)
scheduler.enrichLimit2120Макс. параллельных обогащений
scheduler.catalogKeepPerSeller101100Файлов сканов на продавца
scheduler.enrichedKeepPerSeller301200Файлов обогащений на продавца
scheduler.morningSummaryUtcHour5023Час утренней сводки (UTC)
scheduler.morningSummaryUtcMinute0059Минута утренней сводки (UTC)

Параметры без hot-reload

Применяются после перезапуска watcher-bot.service. Это интервалы setInterval, которые устанавливаются однократно при scheduler.start().

ПараметрПо умолчаниюМинМаксОписание
scheduler.scheduleCheckIntervalMs300 000 (5 мин)10 0003 600 000Проверка расписаний сканов
scheduler.enrichCheckIntervalMs300 000 (5 мин)10 0003 600 000Проверка расписаний обогащения
scheduler.tryRunNextIntervalMs30 000 (30 сек)5 000600 000Цикл запуска из очереди
scheduler.monitorIntervalMs15 000 (15 сек)5 000300 000Мониторинг ПК
scheduler.rotationIntervalMs86 400 000 (24 ч)3 600 000604 800 000Ротация файлов

2.6 Обработка ошибок

На уровне бота

СитуацияПоведение
Неизвестная командаОтвет: ❓ Неизвестная команда. /help для списка.
Продавец не найденПоиск по всем маркетплейсам; если не найден: ❌ Продавец X не найден
Нет свободных ПК при /scanЗадача добавляется в очередь: ⏳ Нет свободных ПК. Добавлен в очередь.
Нет свободных ПК при быстром сканеСообщение: ⏳ Нет свободных ПК. Попробуйте позже.
Нет скана для /enrich❌ Нет завершённого скана. Сначала /scan <id>
Обогащение уже запущено⏳ Обогащение для X уже в процессе

На уровне планировщика

СитуацияПоведение
CDP Pool недоступен при tryRunNextFallback: если runner не занят, пытается запустить одну задачу
Оркестратор вернул nullЗадача пропускается в текущем цикле, будет повторена через 30 сек
Ошибка запуска задачиdb.updateScanFailed, лог в консоль
CDP Pool недоступен при monitorBrowserПропуск цикла мониторинга
Нет файла скана для автообогащенияПропуск задачи с логом: Пропуск автообогащения: нет файла скана

При рестарте процесса

Все задачи со статусом running помечаются как failed с сообщением Orphaned (bot restart). Это предотвращает зависание очереди.


2.7 Экспортируемые функции

bot.js

Не экспортирует функций — является точкой входа (node bot.js).

Внутренние функции, доступные обработчикам:

ФункцияОписание
isAdmin(msg)Проверка msg.chat.id === ADMIN_CHAT_ID
sendAlert(text)Отправка Markdown-сообщения в ADMIN_CHAT_ID
startQuickScan(msg, sellerId, marketplace)Полный цикл быстрого скана: проверка ПК, автосоздание продавца, resume, запуск

scheduler.js

ФункцияОписание
start()Запуск всех 6 циклов
setAlertFn(fn)Установка функции для отправки алертов (передаётся sendAlert из bot.js)
setSendFileFn(fn)Установка функции для отправки файлов (передаётся bot.sendDocument)
tryRunNext()Ручной вызов цикла запуска (используется из /enrich для немедленного старта)
getMorningSummary()Генерация текста утренней сводки (используется в /summary)

Документ подготовлен: Февраль 2026
Версия: 4.0
Статус: Черновик

Документация ADOLF Platform