Документация Блока 3 и версия 0.3.5
- docs/events.md дополнен схемой ClickHouse, агрегатами, регламентом хранения и списком уведомлений в чат логов - README описывает аналитику, уведомления, бэкап событий и структуру проекта - DEPLOY.md описывает сервис ClickHouse, проверку, настройку бэкапа и cron - примеры сообщений коммитов приведены к стилю без префиксов - версия 0.3.5
This commit is contained in:
parent
dbf78aa1d5
commit
cd9004c10f
71
DEPLOY.md
71
DEPLOY.md
|
|
@ -15,9 +15,13 @@ cd DispelEvilBot
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp env/test.env.example env/test.env
|
cp env/test.env.example env/test.env
|
||||||
# заполнить: BOT_TOKEN, DB_PASSWORD, CHAT_ID (основной чат), ALERT_CHAT_ID (опц.), ADMIN_IDS (опц.)
|
# заполнить: BOT_TOKEN, DB_PASSWORD, CHAT_ID (основной чат), ALERT_CHAT_ID (опц.),
|
||||||
|
# ADMIN_IDS (опц.), CLICKHOUSE_PASSWORD (аналитика событий)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Порт ClickHouse на хосте (`CLICKHOUSE_HTTP_PORT`) у контуров должен различаться:
|
||||||
|
`prod` — `8123`, `test` — `8124` (иначе контейнеры конфликтуют на одной VPS).
|
||||||
|
|
||||||
## 3. Логин в registry (если пакет приватный)
|
## 3. Логин в registry (если пакет приватный)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -46,7 +50,62 @@ docker compose -p test --env-file env/test.env -f docker-compose.prod.yml logs -
|
||||||
|
|
||||||
1. `postgres` поднимается и проходит healthcheck;
|
1. `postgres` поднимается и проходит healthcheck;
|
||||||
2. `migrate` (**Flyway**) накатывает миграции из `sql/` — для пустой БД с нуля;
|
2. `migrate` (**Flyway**) накатывает миграции из `sql/` — для пустой БД с нуля;
|
||||||
3. `bot` стартует (`Запуск DispelEvilBot v<версия> (APP_ENV=...)`).
|
3. `clickhouse` поднимается и применяет `clickhouse/init/001_events.sql` —
|
||||||
|
**только при первой инициализации** пустого data-каталога;
|
||||||
|
4. `bot` стартует (`Запуск DispelEvilBot v<версия> (APP_ENV=...)`), аналитика и рассылки — в нём же.
|
||||||
|
|
||||||
|
Проверка контура (сервисы, миграции, Postgres, ClickHouse):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make check E=test
|
||||||
|
```
|
||||||
|
|
||||||
|
## ClickHouse (аналитика событий)
|
||||||
|
|
||||||
|
События всех действий бота пишутся в `analytics.events` (контракт — [`docs/events.md`](docs/events.md)).
|
||||||
|
ClickHouse наружу **не публикуется**: только loopback хоста (`127.0.0.1:${CLICKHOUSE_HTTP_PORT}`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make ch E=test # clickhouse-client контура
|
||||||
|
# пример: события за сегодня по типам
|
||||||
|
docker compose -p test --env-file env/test.env -f docker-compose.prod.yml exec -T clickhouse \
|
||||||
|
clickhouse-client --user "$CLICKHOUSE_USER" --password "$CLICKHOUSE_PASSWORD" \
|
||||||
|
--query "SELECT event_type, count() FROM analytics.events WHERE toDate(event_time) = today() GROUP BY event_type"
|
||||||
|
```
|
||||||
|
|
||||||
|
Если ClickHouse недоступен, бот продолжает работать: события уходят в stdout (WARNING),
|
||||||
|
полностью выключить можно флагом `CLICKHOUSE_ENABLED=false`.
|
||||||
|
|
||||||
|
Изменения схемы: `clickhouse/init/*.sql` применяются лишь на пустом data-каталоге,
|
||||||
|
поэтому на существующем контуре DDL нужно применить вручную (`make ch E=...`).
|
||||||
|
|
||||||
|
## Бэкап событий на домашний сервер
|
||||||
|
|
||||||
|
Сырые события живут на VPS ограниченное время: раз в сутки вчерашняя партиция
|
||||||
|
выгружается в `Parquet.gz`, передаётся на домашний сервер, импортируется в тамошний
|
||||||
|
ClickHouse и сверяется по количеству строк — **только после сверки** партиции старше
|
||||||
|
`BACKUP_GRACE_DAYS` (по умолчанию 7) удаляются на VPS. На VPS остаются агрегаты
|
||||||
|
(`events_daily`, `money_daily`).
|
||||||
|
|
||||||
|
Разовая настройка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp env/backup.env.example env/backup.env # BACKUP_REMOTE, BACKUP_DIR, BACKUP_SSH_KEY, ...
|
||||||
|
# на домашнем сервере (в каталоге, куда кладутся архивы) разместить:
|
||||||
|
# scripts/clickhouse_import.sh
|
||||||
|
# clickhouse/init/001_events.sql -> как 001_events.sql рядом со скриптом
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверочный прогон (без cron): `make backup E=test`.
|
||||||
|
|
||||||
|
Cron на VPS (вчерашний день уже закрыт, время московское):
|
||||||
|
|
||||||
|
```cron
|
||||||
|
0 4 * * * cd /opt/DispelEvilBot && ./scripts/clickhouse_backup.sh test >> /var/log/clickhouse-backup-test.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
Ошибка на любом шаге оставляет данные на VPS (партиции не удаляются) и пишет понятный лог.
|
||||||
|
Импорт дня идемпотентен: повторный прогон не дублирует строки.
|
||||||
|
|
||||||
## Обновление и откат
|
## Обновление и откат
|
||||||
|
|
||||||
|
|
@ -67,7 +126,13 @@ docker compose -p <контур> --env-file env/<контур>.env -f docker-com
|
||||||
|
|
||||||
## Переменные окружения
|
## Переменные окружения
|
||||||
|
|
||||||
См. `env/prod.env.example` / `env/test.env.example`.
|
См. `env/prod.env.example` / `env/test.env.example` (контуры) и `env/backup.env.example` (бэкап событий).
|
||||||
|
|
||||||
|
## Дашборд (позже)
|
||||||
|
|
||||||
|
Superset поднимается на домашнем сервере и читает **локальный** ClickHouse с полной
|
||||||
|
историей событий (сюда ежедневно приезжают архивы). Отдельный read-only пользователь
|
||||||
|
ClickHouse и сам дашборд — финальный этап, в этот контур не входят.
|
||||||
|
|
||||||
## Перенос данных на прод (позже, короткое окно простоя)
|
## Перенос данных на прод (позже, короткое окно простоя)
|
||||||
|
|
||||||
|
|
|
||||||
49
README.md
49
README.md
|
|
@ -6,9 +6,12 @@ Telegram-бот клана Dispel Evil (aiogram 3 + Postgres). Монорепо
|
||||||
## Структура
|
## Структура
|
||||||
|
|
||||||
```
|
```
|
||||||
common/ # общий пакет: config, logging, db, repositories, models, texts
|
common/ # общий пакет: config, logging, db, repositories, models, texts, analytics
|
||||||
bot/ # сервис бота: handlers, services, keyboards, notifications
|
bot/ # сервис бота: handlers, services, keyboards, middlewares, notifications
|
||||||
sql/ # миграции Flyway (V__*.sql, R__*.sql)
|
sql/ # миграции Flyway (V__*.sql, R__*.sql)
|
||||||
|
clickhouse/ # init-скрипты ClickHouse (схема аналитики)
|
||||||
|
docs/ # документация (docs/events.md — события аналитики)
|
||||||
|
scripts/ # эксплуатационные скрипты (проверка контура, бэкап событий)
|
||||||
images/ # статичные картинки (приветствие)
|
images/ # статичные картинки (приветствие)
|
||||||
deploy/ # материалы деплоя (Caddyfile, инструкции)
|
deploy/ # материалы деплоя (Caddyfile, инструкции)
|
||||||
tests/ # тесты
|
tests/ # тесты
|
||||||
|
|
@ -21,6 +24,7 @@ docker-compose.yml / docker-compose.prod.yml
|
||||||
|
|
||||||
- Python 3.12
|
- Python 3.12
|
||||||
- PostgreSQL 14+
|
- PostgreSQL 14+
|
||||||
|
- ClickHouse 25.3 (аналитика событий; можно выключить — `CLICKHOUSE_ENABLED=false`)
|
||||||
|
|
||||||
## Настройка
|
## Настройка
|
||||||
|
|
||||||
|
|
@ -44,9 +48,25 @@ APP_ENV=prod python -m bot # prod
|
||||||
Схема управляется миграциями **Flyway** в `sql/` (`V__*.sql` — versioned, `R__*.sql` — repeatable).
|
Схема управляется миграциями **Flyway** в `sql/` (`V__*.sql` — versioned, `R__*.sql` — repeatable).
|
||||||
При Docker-развёртывании накат выполняется автоматически сервисом `migrate` перед ботом.
|
При Docker-развёртывании накат выполняется автоматически сервисом `migrate` перед ботом.
|
||||||
|
|
||||||
|
## Аналитика (ClickHouse)
|
||||||
|
|
||||||
|
Все значимые действия бота пишутся в ClickHouse в единую таблицу `analytics.events`.
|
||||||
|
Контракт событий — [`docs/events.md`](docs/events.md) (типы, payload, примеры запросов).
|
||||||
|
|
||||||
|
- схема — `clickhouse/init/001_events.sql` (применяется при первой инициализации контейнера);
|
||||||
|
- клиент и батчинг — `common/analytics/` (запись неблокирующая, сбой ClickHouse не влияет на бота);
|
||||||
|
- сырые события живут на VPS 7 дней и ежедневно уезжают архивом на домашний сервер,
|
||||||
|
на VPS остаются агрегаты (`events_daily`, `money_daily`) — см. [DEPLOY.md](DEPLOY.md);
|
||||||
|
- выключается флагом `CLICKHOUSE_ENABLED=false`.
|
||||||
|
|
||||||
|
## Уведомления в чат логов
|
||||||
|
|
||||||
|
В `ALERT_CHAT_ID` (если задан) уходят: вход и выход участников, успешные очищения и
|
||||||
|
ежечасный пинг «бот живой». Отправка не критична: ошибки только пишутся в лог.
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
Локальный запуск (postgres + migrate + bot):
|
Локальный запуск (postgres + migrate + clickhouse + bot):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env # заполнить
|
cp .env.example .env # заполнить
|
||||||
|
|
@ -71,9 +91,20 @@ black --check .
|
||||||
pytest
|
pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Бэкап событий
|
||||||
|
|
||||||
|
Сырые события ClickHouse ежедневно выгружаются архивом на домашний сервер (по cron),
|
||||||
|
на VPS остаются только агрегаты и последние дни сырых данных:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make backup E=test # ./scripts/clickhouse_backup.sh test
|
||||||
|
```
|
||||||
|
|
||||||
|
Настройка и расписание — см. [`DEPLOY.md`](DEPLOY.md).
|
||||||
|
|
||||||
## Версионирование
|
## Версионирование
|
||||||
|
|
||||||
- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.3.4`.
|
- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.3.5`.
|
||||||
- Схема — SemVer-подобная (`MAJOR.MINOR.PATCH`); git-тег = `v` + версия (`v0.1`).
|
- Схема — SemVer-подобная (`MAJOR.MINOR.PATCH`); git-тег = `v` + версия (`v0.1`).
|
||||||
- Docker-образы тегируются версией (Блок 2), события ClickHouse получают `bot_version` (Блок 3).
|
- Docker-образы тегируются версией (Блок 2), события ClickHouse получают `bot_version` (Блок 3).
|
||||||
- Выпуск: изменить `common/version.py` → коммит → аннотированный тег `vX.Y` → `git push --tags`.
|
- Выпуск: изменить `common/version.py` → коммит → аннотированный тег `vX.Y` → `git push --tags`.
|
||||||
|
|
@ -90,14 +121,14 @@ pytest
|
||||||
- Переход на «ветки + PR» и защиту ветки — когда появится второй разработчик.
|
- Переход на «ветки + PR» и защиту ветки — когда появится второй разработчик.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# обычная работа
|
# обычная работа: сообщение без префиксов, по существу изменения
|
||||||
git add -A
|
git add -A
|
||||||
git commit -m "feat: ..."
|
git commit -m "Краткое описание изменения"
|
||||||
git push origin master
|
git push origin master
|
||||||
|
|
||||||
# выпуск релиза
|
# выпуск релиза
|
||||||
# 1) поднять __version__ в common/version.py
|
# 1) поднять __version__ в common/version.py
|
||||||
git commit -am "chore: bump version to X.Y"
|
git commit -am "Версия X.Y"
|
||||||
git tag -a vX.Y -m "Release vX.Y"
|
git tag -a vX.Y -m "Release vX.Y"
|
||||||
git push origin master --tags
|
git push origin master --tags
|
||||||
```
|
```
|
||||||
|
|
@ -109,4 +140,6 @@ git push origin master --tags
|
||||||
|
|
||||||
## Переменные окружения
|
## Переменные окружения
|
||||||
|
|
||||||
См. `.env.example`.
|
- общие — `.env.example` (включая `CLICKHOUSE_*` и параметры батчинга `ANALYTICS_*`);
|
||||||
|
- контуры — `env/prod.env.example`, `env/test.env.example`;
|
||||||
|
- бэкап событий — `env/backup.env.example`.
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
__version__ = "0.3.4"
|
__version__ = "0.3.5"
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,48 @@
|
||||||
> Расхождение со списком ниже ловит `tests/test_analytics.py`.
|
> Расхождение со списком ниже ловит `tests/test_analytics.py`.
|
||||||
> Добавляешь событие — добавь строку в таблицу.
|
> Добавляешь событие — добавь строку в таблицу.
|
||||||
|
|
||||||
|
## Схема в ClickHouse
|
||||||
|
|
||||||
|
DDL — `clickhouse/init/001_events.sql` (применяется при первой инициализации контейнера).
|
||||||
|
|
||||||
|
- `analytics.events` — сырые события, `MergeTree`, `PARTITION BY toYYYYMMDD(event_time)`,
|
||||||
|
`ORDER BY (event_time, event_type, user_id)`. Партиционирование по дню выбрано специально:
|
||||||
|
сырые партиции ежедневно удаляются после бэкапа (дешёвый `DROP PARTITION`, без mutation).
|
||||||
|
- `analytics.events_daily` — агрегат (`SummingMergeTree`): `day`, `event_type`, `user_id`,
|
||||||
|
`chat_id`, `events`. Строится материализованным представлением `events_daily_mv`.
|
||||||
|
- `analytics.money_daily` — агрегат по деньгам: `day`, `event_type`, `user_id`,
|
||||||
|
`amount_sum`, `events` (из `payload.amount` событий `money_accrual`/`money_spend`).
|
||||||
|
|
||||||
|
Агрегаты остаются на VPS навсегда, поэтому активность, топ команд и денежные потоки
|
||||||
|
доступны и после удаления сырых событий. Запросы к агрегатам суммируют `events`/`amount_sum`
|
||||||
|
(фон слияний `SummingMergeTree` не гарантирует полную свёртку в любой момент).
|
||||||
|
|
||||||
|
## Хранение и бэкап
|
||||||
|
|
||||||
|
| Что | Где | Сколько |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Сырые события | VPS, `analytics.events` | последние `BACKUP_GRACE_DAYS` дней (по умолчанию 7) |
|
||||||
|
| Агрегаты | VPS | постоянно |
|
||||||
|
| Полная история | домашний сервер, свой ClickHouse | архивы `events_YYYY-MM-DD.parquet.gz` (ежедневно) |
|
||||||
|
|
||||||
|
Каждую ночь (по Москве) `scripts/clickhouse_backup.sh` выгружает вчерашнюю партицию,
|
||||||
|
передаёт её на домашний сервер, импортирует и **сверяет количество строк**; только после
|
||||||
|
успешной сверки на VPS удаляются партиции старше грейса. Ошибка бэкапа данные не удаляет.
|
||||||
|
Подробности — `DEPLOY.md`.
|
||||||
|
|
||||||
|
## Уведомления в чат логов
|
||||||
|
|
||||||
|
Помимо записи в ClickHouse часть событий дублируется сообщением в `ALERT_CHAT_ID`
|
||||||
|
(если он задан; `0` — выключено). Отправка не критична: ошибки только логируются.
|
||||||
|
|
||||||
|
| Уведомление | Когда | Событие в ClickHouse |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Вход участника | кто-то вошёл в основной чат | `join` |
|
||||||
|
| Выход участника | кто-то вышел из основного чата | `leave` |
|
||||||
|
| Очищение | успешное `/очищение` (`+опыт`, `+монеты`) | `purification` |
|
||||||
|
| Пинг «бот живой» | раз в час | `bot_alive` |
|
||||||
|
| Попытка доступа извне | не участник чата стучится в бота | `access_denied` |
|
||||||
|
|
||||||
## Поля события
|
## Поля события
|
||||||
|
|
||||||
| Поле | Тип | Описание |
|
| Поле | Тип | Описание |
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ from common import __version__
|
||||||
|
|
||||||
def test_version_is_set():
|
def test_version_is_set():
|
||||||
assert __version__
|
assert __version__
|
||||||
assert __version__ == "0.3.4"
|
assert __version__ == "0.3.5"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue