Files
new_lottery_bot/docs/CHAT_SCHEDULER.md
Andrew K. Choi a0e6a385b6
Some checks reported errors
continuous-integration/drone/push Build encountered an error
docs: добавлена документация по планировщику рассылки
- Подробное описание работы планировщика с пакетной отправкой
- Математика расчета скорости отправки (10-13 сообщений/сек)
- Рекомендации по настройке параметров BATCH_SIZE и BATCH_DELAY
- Примеры для разных размеров групп пользователей
- Troubleshooting распространенных проблем
- Объяснение защиты от блокировки Telegram (лимит 30 сообщений/сек)
2025-11-16 14:37:20 +09:00

290 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Настройка планировщика рассылки
## Проблема
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
```
Это обеспечивает баланс между скоростью и безопасностью.