Как можно исправить ошибку "Unclosed client session" в aiohttp?

Я пытался интегрировать базу данных с ботом в Telegram, но при создании `AsyncEngine` сталкиваюсь с ошибкой "Unclosed client session" от aiohttp. Вот сообщение об ошибке:

```
2024-11-29 23:12:11,717 - ERROR - asyncio - (base_events.py).default_exception_handler(1738) - Unclosed client session
client_session:
2024-11-29 23:12:11,848 - ERROR - asyncio - (base_events.py).default_exception_handler(1738) - Unclosed client session
client_session:
2024-11-29 23:12:11,849 - ERROR - asyncio - (base_events.py).default_exception_handler(1738) - Unclosed connector
connections: ['[(, 1.851338541)]']
connector:
```

Я не могу понять, в чем заключается проблема. Буду очень признателен за помощь.

Вот код из `main.py`:

```python
async def main():
    postgres_url = URL.create(...)
    async_engine = await create_async_engine(postgres_url)
    await proceed_schemas(async_engine, BaseModel.metadata)
    await dp.start_polling(bot)
```

И код из `engine.py`:

```python
async def create_async_engine(url: Union[URL, str]) -> AsyncEngine:
    return _create_async_engine(url=url, echo=True, encoding='utf-8', pool_pre_ping=True)
```
  • 29 ноября 2024 г. 20:33
Ответы на вопрос 2
Ошибка "Unclosed client session" в aiohttp возникает, когда сессия клиента не закрыта после завершения работы с ним. Это может произойти, если вы создаете клиентские сессии без соответствующего закрытия.

В вашем случае вы используете `create_async_engine` и, вероятно, где-то в коде (может быть, в других частях вашего проекта или библиотеке) создаете сессию aiohttp, не закрывая ее. Давайте рассмотрим, как это можно исправить.

### 1. Убедитесь, что сессия закрыта

Если вы создаете клиентскую сессию предварительно, убедитесь, что вы закрываете ее после использования. Например:

```python
import aiohttp

async def fetch_data(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()
```

### 2. Используйте контекстный менеджер с `AsyncEngine`

Если вы используете SQLAlchemy с `asyncio`, создайте `AsyncSession` с помощью контекстного менеджера:

```python
from sqlalchemy.ext.asyncio import AsyncSession

async by using the context manager when interacting with the database:
async with async_engine.begin() as conn:
    async with AsyncSession(conn) as session:
        # Ваш код для работы с результатами запроса
```

### 3. Отладьте и проверьте закрытие

Убедитесь, что все используемые вами клиентские сессии (aiohttp) закрываются в конце вашего приложения. Если вы создаете сессию на уровне модуля или приложения, вам может потребоваться убирать её из памяти, когда она больше не нужна.

### 4. Используйте функцию "shutdown" в ваших асинхронных приложениях

При завершении вашего приложения вы можете добавлять функцию "shutdown", которая будет закрывать все открытые сессии и соединения.

```python
async def shutdown():
    # Закрываем любую глобальную сессию aiohttp
    if hasattr(your_app, 'client_session'):
        await your_app.client_session.close()

# Ваша точка входа
async def main():
    try:
        ...
    finally:
        await shutdown()
```

### 5. Разделяйте ответственность 

Рекомендуется создавать и закрывать `ClientSession` непосредственно в нужном месте, как показано выше, чтобы уменьшить шансы на "Unclosed client session".

### 6. Проверка других библиотек

Если вы используете библиотеки, которые зависят от aiohttp (например, для ботов, работающих с Telegram), убедитесь, что в них также управляется сессиями должным образом.

### Пример исправленного кода

Вот ваш исходный код с внесенными изменениями для обработки сессий:

```python
# engine.py
import aiohttp

async def create_async_engine(url: Union[URL, str]) -> AsyncEngine:
    # Возможно, создание сессии здесь следует передать на уровень вызова
    return _create_async_engine(url=url, echo=True, encoding='utf-8', pool_pre_ping=True)

# main.py
from aiohttp import ClientSession

async def main():
    postgres_url = URL.create(...)
    async_engine = await create_async_engine(postgres_url)

    async with ClientSession() as session:
        # Используйте сессию для ваших запросов
        await proceed_schemas(async_engine, BaseModel.metadata)

    await dp.start_polling(bot)

```

### Заключение

Убедитесь, что вы правильно закрываете все созданные сессии и используете подходящие контекстные менеджеры. Это поможет избежать ошибок, связанных с "Unclosed client session".
Все оказалось невероятно банально,  create_async_engine из sqlalchemy не принимает аргумент encoding. Убрал его и все заработало
Похожие вопросы