refactor
This commit is contained in:
85
docs/ASYNCIO_FIX_REPORT.md
Normal file
85
docs/ASYNCIO_FIX_REPORT.md
Normal file
@@ -0,0 +1,85 @@
|
||||
````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}
|
||||
```
|
||||
|
||||
Бот успешно запускается и работает стабильно в продакшене.
|
||||
````
|
||||
Reference in New Issue
Block a user