AI Asist
v2
Д
Д

Автоматический сбор на Hetzner

← Заметки  ·  Раздел: Ops  ·  Файл: data/notes/ops/cron-hetzner.md

Автоматический сбор на Hetzner

Что и когда запускается на боевом сервере. Актуализировано 26.08.2026 по факту (systemctl list-timers, unit-файлы в /etc/systemd/system).

Главное

🔴 Расписание живёт в systemd-таймерах, а не в crontab. В crontab лежит только утренняя сводка операционки (/root/ops/bot/opsbot.py), к mp-system она не относится. Новую регулярную задачу заводить таймером, а не строкой в crontab — иначе она выпадет из общей картины и не будет видна в list-timers.

  • Рабочая директория: /home/mi/Bot_TG/mp-system, интерпретатор .venv/bin/python.
  • Боевая база: /home/mi/Bot_TG/mp-system/mp.db. ⚠ Локальная mp.dbдругая база.
  • Во всех таймерах OnCalendar задан с Europe/Moscow: сервер живёт в CEST/CET, без явной зоны время поедет при переходе на зимнее.

Расписание

Время МСК Unit Что делает
01:00 mp-collect@3, mp-collect@5 ежедневный сбор WB (Siluetta, Tote)
02:00 mp-collect-ozon@2, mp-collect-ozon@4 ежедневный сбор Ozon
02:10 ozon-sku-traffic-snapshot трафик карточек Ozon
02:30 mp-report-cache кэш Telegram-отчётов
03:00 mp-signal дайджест «сигнал или шум»
03:30 mp-warehouse-sheet синхронизация своего склада с Google Sheets
12:00 mp-finreport@3, mp-finreport@5 финреп WB (реализация)
12:30 mp-report-cache кэш отчётов, второй прогон
каждые 3 ч marketplace-returns-collect история возвратов Ozon/WB
ежечасно mp-db-sync синк mp.db на ru-web (демо)

Persistent: где true, а где false — и почему

Persistent=true означает «если сервер спал, догнать пропущенный запуск при старте».

  • true у сбора, кэша, сигнала и синка склада — пропущенный день лучше догнать; у Google Sheets лимитов запросов нет, догоняющий прогон безвреден.
  • 🔴 false у mp-finreport@ намеренно: finance-api WB даёт 2 запроса в 24 ч. Если сервер спал в 12:00, догоняющий запуск при включении сожжёт лимит впустую. То же соображение у ozon-sku-traffic-snapshot.

Заводя новый таймер, решать этот вопрос осознанно: есть ли у источника лимит и вредит ли запоздалый прогон.

Лимиты WB, из-за которых нельзя двигать расписание вслепую

  • seller-analytics (воронка) — ~2 запроса/час;
  • advert-api — общий bucket, не гонять параллельно со сбором;
  • finance-api — 2 запроса/24 ч, интервал 12 ч;
  • stocks/orders/sales — щадящие.

Поэтому WB-магазины разведены по минутам (RandomizedDelaySec=120), а finreport вынесен в отдельный полуденный таймер.

Синхронизация склада — что делает mp-warehouse-sheet

scripts/import_warehouse_sheet.py --apply --alert --max-delta 200

Пишет в mp.db движения adjust / return по расхождению с Google-таблицей.

🔴 --max-delta 200 — порог вменяемости. Суммарная дельта больше 200 шт не записывается: скрипт шлёт алерт и выходит с кодом 3, systemd помечает запуск упавшим. 200 выбрано потому, что самая крупная разовая отгрузка была 170 шт — всё, что больше, скорее авария в листе, чем день работы. Настоящее крупное расхождение проводится вручную: --max-delta 0.

⚠ Порог не защищает от подмены значения внутри него: 220 → 180 пройдёт как обычная убыль. Это ловится только глазами.

Алерты: шлём при записи движений и при отказе/ошибке. Молчим, когда расхождений нет — в отличие от run_collect, который шлёт хартбит каждый раз. Плата за это: тишина двусмысленна (то ли сошлось, то ли таймер умер), поэтому при сомнении смотреть systemctl list-timers.

Как посмотреть и как чинить

ssh hetzner
systemctl list-timers --all --no-pager | grep -E 'mp-|marketplace-|ozon-'
systemctl status mp-collect@3.service
journalctl -u mp-collect@3.service -n 100 --no-pager

Ручной прогон одной задачи:

sudo systemctl start mp-collect@3.service

Как завести новый таймер

  1. /etc/systemd/system/<имя>.serviceType=oneshot, WorkingDirectory=/home/mi/Bot_TG/mp-system, ExecStart=/home/mi/Bot_TG/mp-system/.venv/bin/python scripts/<скрипт>.py.
  2. /etc/systemd/system/<имя>.timerOnCalendar с Europe/Moscow, Persistent по правилу выше, RandomizedDelaySec если задач несколько.
  3. systemctl daemon-reload && systemctl enable --now <имя>.timer.
  4. Проверить: systemctl list-timers | grep <имя> и разовый systemctl start <имя>.service.
  5. Вписать в таблицу выше.

⚠ Systemd сам не запустит второй экземпляр, пока работает первый, — отдельный лок не нужен.

⚠ Новый регулярный джоб — зона /grill-me (правило из корневого CLAUDE.md): где запускается, что если предыдущий не закончился, кому идёт алерт при падении.

Фильтры