feature/chat-system #1

Merged
trevor merged 11 commits from feature/chat-system into master 2025-11-17 00:32:48 +00:00
9 changed files with 2062 additions and 1 deletions
Showing only changes of commit a0e6a385b6 - Show all commits

289
docs/CHAT_SCHEDULER.md Normal file
View File

@@ -0,0 +1,289 @@
# Настройка планировщика рассылки
## Проблема
Telegram имеет лимиты на количество отправляемых сообщений:
- **30 сообщений в секунду** для ботов
- При превышении возникает ошибка `Too Many Requests` (код 429)
- Бот может быть временно заблокирован
## Решение
Реализован **планировщик пакетной рассылки** с контролируемой задержкой между пакетами.
### Параметры планировщика
```python
# В файле src/handlers/chat_handlers.py
BATCH_SIZE = 20 # Количество сообщений в одном пакете
BATCH_DELAY = 1.0 # Задержка между пакетами в секундах
```
### Как это работает
1. **Получение списка пользователей:**
- Загружаются все зарегистрированные пользователи (`is_registered=True`)
- Исключается отправитель сообщения
2. **Разбиение на пакеты:**
- Пользователи разбиваются на группы по `BATCH_SIZE` (по умолчанию 20)
- Например, 100 пользователей = 5 пакетов по 20
3. **Параллельная отправка внутри пакета:**
- В каждом пакете сообщения отправляются параллельно через `asyncio.gather()`
- Это ускоряет доставку без превышения лимитов
4. **Задержка между пакетами:**
- После отправки пакета выжидается `BATCH_DELAY` секунд
- Это предотвращает превышение лимита 30 сообщений/сек
5. **Обработка ошибок:**
- Ошибки отправки отлавливаются для каждого пользователя
- Статистика успешных/неуспешных доставок ведется отдельно
### Математика
**Скорость отправки:**
- Пакет из 20 сообщений отправляется параллельно ≈ за 0.5-1 секунду
- Задержка между пакетами: 1 секунда
- Итого: **~20 сообщений за 1.5-2 секунды** = **10-13 сообщений/сек**
- Это в **2-3 раза меньше** лимита Telegram (30/сек)
**Пример для 100 пользователей:**
- 5 пакетов по 20 сообщений
- Время отправки: 5 × (1 сек отправка + 1 сек задержка) = **10 секунд**
- Средняя скорость: 10 сообщений/сек
**Пример для 1000 пользователей:**
- 50 пакетов по 20 сообщений
- Время отправки: 50 × 2 сек = **100 секунд (1.5 минуты)**
- Средняя скорость: 10 сообщений/сек
### Настройка параметров
#### Увеличение скорости
Если нужно быстрее рассылать и у вас стабильное соединение:
```python
BATCH_SIZE = 25 # Больше сообщений в пакете
BATCH_DELAY = 0.8 # Меньше задержка
```
⚠️ **Риск:** При > 30 сообщений/сек может быть блокировка
#### Уменьшение нагрузки
Если возникают ошибки 429 или нестабильное соединение:
```python
BATCH_SIZE = 15 # Меньше сообщений в пакете
BATCH_DELAY = 1.5 # Больше задержка
```
**Безопаснее:** Меньше шанс блокировки
#### Для VIP ботов (верифицированных)
Telegram может повысить лимиты для верифицированных ботов:
```python
BATCH_SIZE = 30 # Можно больше
BATCH_DELAY = 0.5 # Можно быстрее
```
## Пример работы
### Код функции
```python
async def broadcast_message_with_scheduler(message: Message, exclude_user_id: Optional[int] = None):
"""Разослать сообщение всем пользователям с планировщиком"""
async with async_session_maker() as session:
users = await get_all_active_users(session)
if exclude_user_id:
users = [u for u in users if u.telegram_id != exclude_user_id]
forwarded_ids = {}
success_count = 0
fail_count = 0
# Разбиваем на пакеты
for i in range(0, len(users), BATCH_SIZE):
batch = users[i:i + BATCH_SIZE]
# Отправляем пакет параллельно
tasks = [_send_message_to_user(message, u.telegram_id) for u in batch]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Подсчитываем статистику
for user, result in zip(batch, results):
if isinstance(result, Exception):
fail_count += 1
elif result is not None:
forwarded_ids[str(user.telegram_id)] = result
success_count += 1
else:
fail_count += 1
# Задержка между пакетами
if i + BATCH_SIZE < len(users):
await asyncio.sleep(BATCH_DELAY)
return forwarded_ids, success_count, fail_count
```
### Статистика для пользователя
После рассылки пользователь видит:
```
✅ Сообщение разослано!
📤 Доставлено: 95
Не доставлено: 5
```
**Причины неуспешной доставки:**
- Пользователь заблокировал бота
- Пользователь удалил аккаунт
- Временные сетевые проблемы
- Ограничения Telegram на стороне получателя
## История сообщений
Все ID отправленных сообщений сохраняются в БД:
```sql
-- Таблица chat_messages
forwarded_message_ids JSONB
-- Пример данных:
{
"123456789": 12345, -- telegram_id: message_id
"987654321": 12346,
"555555555": 12347
}
```
Это позволяет:
- Удалять сообщения у всех пользователей через `/delete_msg`
- Отслеживать кому было доставлено сообщение
- Собирать статистику рассылок
## Рекомендации
### Для маленьких групп (< 50 пользователей)
Можно использовать параметры по умолчанию:
```python
BATCH_SIZE = 20
BATCH_DELAY = 1.0
```
### Для средних групп (50-200 пользователей)
Рекомендуется:
```python
BATCH_SIZE = 20
BATCH_DELAY = 1.0
```
Время рассылки: ~20-40 секунд
### Для больших групп (200-1000 пользователей)
Рекомендуется:
```python
BATCH_SIZE = 25
BATCH_DELAY = 1.0
```
Время рассылки: ~1.5-3 минуты
### Для очень больших групп (> 1000 пользователей)
Рассмотрите:
- Увеличение `BATCH_SIZE` до 30
- Использование очередей (RabbitMQ, Celery)
- Распределение нагрузки на несколько ботов
## Мониторинг
Для отслеживания работы планировщика смотрите логи:
```bash
tail -f logs/bot.log | grep "Failed to send"
```
Каждая неуспешная отправка логируется:
```
Failed to send message to 123456789: Forbidden: bot was blocked by the user
Failed to send message to 987654321: Bad Request: chat not found
```
## Тестирование
Для тестирования планировщика:
1. Создайте несколько тестовых аккаунтов
2. Отправьте сообщение через бота
3. Проверьте время доставки и статистику
4. Настройте параметры под свою нагрузку
## Troubleshooting
### Ошибка "Too Many Requests"
**Симптомы:** Бот периодически выдает ошибку 429
**Решение:**
```python
BATCH_SIZE = 15 # Уменьшить размер пакета
BATCH_DELAY = 1.5 # Увеличить задержку
```
### Медленная рассылка
**Симптомы:** Рассылка занимает слишком много времени
**Решение:**
```python
BATCH_SIZE = 25 # Увеличить размер пакета
BATCH_DELAY = 0.8 # Уменьшить задержку
```
⚠️ Следите за ошибками 429!
### Большое количество неуспешных доставок
**Причины:**
- Пользователи массово блокируют бота
- Проблемы с сетью/сервером
- Некорректные telegram_id в базе
**Решение:**
- Регулярно очищайте неактивных пользователей
- Мониторьте состояние сервера
- Валидируйте данные при регистрации
## Итого
**Защита от блокировки**: Лимит 30 сообщений/сек не превышается
**Гибкость**: Легко настроить под свою нагрузку
**Статистика**: Точный подсчет успешных/неуспешных доставок
**История**: Все ID сохраняются для модерации
**Параллелизм**: Быстрая отправка внутри пакета
**Рекомендуемые параметры:**
```python
BATCH_SIZE = 20
BATCH_DELAY = 1.0
```
Это обеспечивает баланс между скоростью и безопасностью.