Синхронизация
Бот и панель — две системы без общей транзакции. Принцип: база бота — источник истины о том, что оплачено; панель — только проекция. Всё остальное на этой странице — механика, которая держит их в согласии.
Panel-first dual-write
Любое провижининг-изменение идёт в строгом порядке: сначала вызов панели (вне DB-транзакции), потом локальный коммит.
- Панель упала во время покупки — покупка не завершается. Пользователь не платит «в пустоту» за подписку, которой нет на панели.
- Panel-write после уже сделанного локального коммита (например,
disableпосле возврата денег) не прошёл — задача уходит в retry-очередь: воркер до 5 раз с backoff повторяет запись, приводя состояние panel-user'а (enabled/disabled) к локальному статусу подписки. Повторы идемпотентны. - Окно «есть на панели, нет локально» (сбой между вызовом панели и коммитом) — документированное и самозалечивается ночной сверкой.
WARNING
Вызов панели никогда не оборачивается в DB-транзакцию — это осознанное решение, а не упущение. Не «чините» это при доработках.
Ноды и сквады — каждые 15 минут
Задача sync_panel_nodes раз в 15 минут зеркалит панель в локальные таблицы:
- Ноды →
server_nodes: имя, страна, адрес, онлайн-юзеры, трафик, статус (ONLINE/OFFLINE; отключённая на панели нода →MAINTENANCE). - Internal squads →
server_squads: имя и число участников. Локальная цена, флаг продажи и заданное вручную отображаемое имя не перезаписываются.
Upsert по UUID панели. Нода, пропавшая из ответа панели, локально не удаляется — помечается OFFLINE, так что флаги «в продаже» и история переживают сбои панели. Тот же синк запускается вручную кнопкой «Синхронизировать» на экране Серверы; статусы нод видны на дашборде кабинета.

Ночная сверка бот ↔ панель
Задача resync_panel ночью (04:17 UTC) сверяет живые подписки с панелью и лечит дрейф — в первую очередь ручные правки на панели. Включается флагом «Ночная сверка с панелью» в кабинете (по умолчанию выключена).
Для каждой активной подписки с panel-user'ом (до 500 за прогон):
| Что нашла сверка | Что делает |
|---|---|
| Panel-user пропал (удалили руками на панели) | Локальная подписка → DISABLED |
| На панели disabled/expired, хотя оплачено | Заново пушит оплаченный спек (лимиты, срок, сквады) и включает пользователя |
| Срок на панели разошёлся с локальным больше чем на сутки | Заново пушит спек |
Исключение: пользователь, которого панель перевела в LIMITED за исчерпание проданного лимита трафика, — это корректная работа панели, а не дрейф; сверка его не включает обратно.
Итог прогона (проверено / восстановлено / пропало из панели) уходит отчётом в топик «alerts» — если было что чинить.
TIP
Вебхук панели (настройка) доносит изменения мгновенно, но не обязателен: 15-минутный синк и ночная сверка закрывают то же самое с задержкой.
