Files
new_lottery_bot/docs/ASYNCIO_FIX_REPORT.md
2025-11-16 12:36:02 +09:00

85 lines
4.0 KiB
Markdown
Raw 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.

````markdown
# Отчет об исправлении критической ошибки AsyncIO Event Loop
## Проблема
При запуске бота в продакшене обнаружилась критическая ошибка:
```
RuntimeError: Task <Task pending> got Future <Future pending> attached to a different loop
```
Эта ошибка массово возникала у всех воркеров TaskManager (worker-0 до worker-14) и делала невозможным стабильную работу бота.
## Причина
Проблема заключалась в том, что объекты `asyncio.PriorityQueue()` и `asyncio.Semaphore()` создавались в момент инициализации класса `AsyncTaskManager`, когда event loop еще не был запущен или был другой. Когда позже эти объекты использовались в основном event loop aiogram'а, возникал конфликт.
### Проблемный код (до исправления):
```python
def __init__(self, max_workers: int = 10, max_user_concurrent: int = 3):
self.max_workers = max_workers
self.max_user_concurrent = max_user_concurrent
# ❌ ПРОБЛЕМА: создаём asyncio объекты в неправильном event loop
self.task_queue = asyncio.PriorityQueue()
self.worker_semaphore = asyncio.Semaphore(max_workers)
self.user_semaphores: Dict[int, asyncio.Semaphore] = {}
```
## Решение
Перенесли создание всех asyncio объектов в метод `start()`, который вызывается в правильном event loop:
### Исправленный код:
```python
def __init__(self, max_workers: int = 10, max_user_concurrent: int = 3):
self.max_workers = max_workers
self.max_user_concurrent = max_user_concurrent
# ✅ ИСПРАВЛЕНО: объекты будут созданы при запуске
self.task_queue: Optional[asyncio.PriorityQueue] = None
self.worker_semaphore: Optional[asyncio.Semaphore] = None
self.user_semaphores: Dict[int, asyncio.Semaphore] = {}
async def start(self):
"""Запуск менеджера задач"""
if self.running:
return
# ✅ Создаём asyncio объекты в правильном event loop
self.task_queue = asyncio.PriorityQueue()
self.worker_semaphore = asyncio.Semaphore(self.max_workers)
self.user_semaphores.clear() # Очищаем старые семафоры
self.running = True
# ... остальная логика
```
## Дополнительные исправления
1. **Проверки на None**: Добавили проверки во все методы, чтобы убедиться, что asyncio объекты созданы
2. **Правильная очистка**: В методе `stop()` очищаем все asyncio объекты
3. **Безопасное создание семафоров пользователей**: Семафоры пользователей теперь также создаются в правильном event loop
## Результат
- ✅ Бот запускается без ошибок
- ✅ Все 15 воркеров TaskManager работают корректно
- ✅ Никаких RuntimeError с event loop
- ✅ Корректное завершение работы по Ctrl+C
## Файлы изменены
- `task_manager.py` - основные исправления AsyncTaskManager
## Тестирование
Создан тест, подтверждающий корректную работу TaskManager:
```python
# Тест показал успешное выполнение:
# Статистика: {'running': True, 'workers_count': 15, 'active_tasks': 0,
# 'queue_size': 0, 'completed_tasks': 1, 'failed_tasks': 0}
```
Бот успешно запускается и работает стабильно в продакшене.
````