refactor
Some checks failed
continuous-integration/drone/pr Build is failing

This commit is contained in:
2026-02-17 00:22:42 +09:00
parent ca0c63a89c
commit 0fdad07d82
36 changed files with 4384 additions and 368 deletions

270
docs/BROADCAST_SYSTEM.md Normal file
View File

@@ -0,0 +1,270 @@
# Система рассылок с Redis очередями
## Обзор
Расширенная система массовых рассылок с поддержкой трех типов рассылки:
- **ЛС пользователям** - массовая рассылка по личным сообщениям с отслеживанием заблокированных
- **В канал** - отправка в Telegram канал
- **В группу** - отправка в Telegram группу
## Основные возможности
### 1. Рассылка в личные сообщения
**Особенности:**
- Использование Redis очередей для управления потоком сообщений
- Автоматическое отслеживание пользователей, заблокировавших бота
- Пакетная отправка с задержками для соблюдения лимитов Telegram
- Детальная обработка ошибок (блокировка, деактивация аккаунта, etc.)
- Автоматическое повторение при FloodWait ошибках
**Технические детали:**
- Размер пакета: 30 сообщений
- Задержка между пакетами: 1 секунда
- Дополнительная задержка при FloodWait: 5 секунд + время из ошибки
### 2. Рассылка в канал/группу
**Особенности:**
- Управление списком каналов и групп через админ-панель
- Проверка прав бота перед добавлением канала
- Возможность добавить описание для каждого канала
- Активация/деактивация каналов
## Архитектура
### Модели данных
#### BroadcastChannel
Хранит информацию о каналах и группах для рассылки:
- `chat_id` - ID чата в Telegram
- `chat_type` - тип (channel/group)
- `title` - название
- `username` - юзернейм (если есть)
- `description` - описание
- `is_active` - активен ли для рассылок
- `added_by` - кто добавил
#### BlockedUser
Отслеживание заблокированных/недоступных пользователей:
- `telegram_id` - ID пользователя
- `error_type` - тип ошибки (blocked_bot, deactivated, not_found, etc.)
- `error_message` - полное сообщение об ошибке
- `first_blocked_at` - первая попытка
- `last_attempt_at` - последняя попытка
- `attempt_count` - количество неудачных попыток
- `is_active` - активна ли блокировка
#### BroadcastLog
История рассылок:
- `broadcast_type` - тип (direct/channel/group)
- `target_id` - ID канала/группы (для соответствующих типов)
- `message_type` - тип сообщения
- `message_text` - текст
- `file_id` - ID файла (если есть)
- Статистика: `total_recipients`, `success_count`, `failed_count`, `blocked_count`
- `created_by` - кто запустил
- `started_at`, `completed_at` - временные метки
- `status` - статус (pending/in_progress/completed/failed)
### Сервисы
#### BroadcastService
Основной сервис для рассылок (`src/core/broadcast_services.py`):
**Методы:**
- `broadcast_to_users()` - рассылка в ЛС
- `broadcast_to_channel()` - отправка в канал/группу
- `send_message_to_user()` - отправка одному пользователю с обработкой ошибок
- `check_user_blocked()` - проверка блокировки
- `mark_user_blocked()` - отметить как заблокированного
- `unblock_user()` - разблокировать
#### RedisQueue
Класс для работы с Redis очередями:
**Методы:**
- `connect()` - подключение к Redis
- `disconnect()` - отключение
- `add_to_queue()` - добавить в очередь
- `get_from_queue()` - получить из очереди (блокирующая)
- `get_queue_length()` - получить длину очереди
- `clear_queue()` - очистить очередь
## Использование
### Добавление канала/группы
1. Перейдите в админ-панель → Массовая рассылка → Управление каналами
2. Нажмите "Добавить канал/группу"
3. Получите ID канала:
- Добавьте бота в канал/группу как администратора
- Перешлите сообщение из канала боту @userinfobot
- Скопируйте ID чата (обычно отрицательное число)
4. Отправьте ID боту
5. При успешной проверке отправьте описание или /skip
### Создание рассылки
1. Перейдите в админ-панель → Массовая рассылка → Создать рассылку
2. Выберите тип рассылки:
- **ЛС пользователям** - всем зарегистрированным
- **В канал** - выберите канал из списка
- **В группу** - выберите группу из списка
3. Отправьте сообщение (текст, фото, видео или документ)
4. Дождитесь завершения и получите статистику
### Просмотр статистики
Перейдите в админ-панель → Массовая рассылка → Статистика:
- Общее количество рассылок
- Количество заблокированных пользователей
- История последних 5 рассылок с детальной статистикой
## Обработка ошибок
Система автоматически обрабатывает следующие типы ошибок:
### TelegramForbiddenError
Пользователь заблокировал бота. Помечается как `blocked_bot`.
### TelegramBadRequest
- `user is deactivated``deactivated`
- `user not found``not_found`
- `chat not found``chat_not_found`
- Остальные → `bad_request`
### TelegramRetryAfter (FloodWait)
Автоматическая задержка и повторная попытка отправки.
### Другие ошибки
Логируются как `unknown_error`.
## Конфигурация
### Переменные окружения
```env
# Redis
REDIS_URL=redis://localhost:6379/0 # По умолчанию
```
### Docker Compose
Redis автоматически запускается при использовании docker-compose:
```yaml
services:
redis:
image: redis:7-alpine
container_name: lottery_redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- lottery_network
```
### Настройки в коде
В `BroadcastService` (`src/core/broadcast_services.py`):
```python
BATCH_SIZE = 30 # Сообщений в пакете
BATCH_DELAY = 1.0 # Задержка между пакетами (секунды)
RETRY_AFTER_DELAY = 5.0 # Дополнительная задержка при FloodWait
```
## Миграция базы данных
Для применения новых таблиц:
```bash
# Применить миграцию
python -m alembic upgrade head
# Откатить миграцию
python -m alembic downgrade -1
```
## Мониторинг
### Логи
Все операции рассылки логируются:
- Успешные отправки (уровень DEBUG)
- Блокировки пользователей (уровень INFO)
- FloodWait задержки (уровень WARNING)
- Ошибки отправки (уровень ERROR)
### База данных
Проверка статистики через SQL:
```sql
-- Количество заблокированных пользователей
SELECT COUNT(*) FROM blocked_users WHERE is_active = true;
-- Статистика рассылок
SELECT
broadcast_type,
COUNT(*) as total,
SUM(success_count) as delivered,
SUM(blocked_count) as blocked
FROM broadcast_logs
GROUP BY broadcast_type;
```
## Рекомендации
1. **Перед запуском большой рассылки:**
- Проверьте количество заблокированных пользователей
- Убедитесь, что Redis работает
- Проверьте логи на наличие ошибок
2. **При добавлении канала:**
- Убедитесь, что бот добавлен как администратор
- Проверьте, что бот имеет права на отправку сообщений
3. **Мониторинг производительности:**
- Следите за временем выполнения рассылок
- При необходимости увеличьте BATCH_SIZE (не более 40)
- Уменьшите BATCH_DELAY при стабильной работе (не менее 0.5 сек)
## Troubleshooting
### Проблема: Рассылка зависает
**Решение:**
1. Проверьте подключение к Redis
2. Проверьте логи на наличие ошибок
3. Убедитесь, что нет FloodWait ошибок
### Проблема: Не удается добавить канал
**Решение:**
1. Убедитесь, что бот добавлен в канал/группу
2. Проверьте права бота (должен быть администратором)
3. Убедитесь, что ID правильный (должен быть отрицательным)
### Проблема: Высокий процент неудач при рассылке
**Решение:**
1. Проверьте количество заблокированных пользователей в статистике
2. Увеличьте BATCH_DELAY для снижения нагрузки
3. Проверьте логи на частые FloodWait ошибки
## Безопасность
- Все операции рассылки доступны только администраторам
- ID каналов/групп хранятся в зашифрованном виде (BigInteger)
- История рассылок связана с администратором, который ее запустил
- Автоматическое логирование всех операций
## Производительность
- Redis очереди обеспечивают асинхронную обработку
- Пакетная отправка снижает нагрузку на API Telegram
- Автоматическое управление задержками предотвращает FloodWait
- Кэширование заблокированных пользователей ускоряет рассылку