Сразу оговорюсь, что я недавно начал изучать
asyncio
и буду рад указанию и объяснению любых допускаемых мною ошибок.
У меня есть скрипт, который берет адреса TON кошельков из БД и делает асинхронные запросы для получения информации о них в индексатор toncenter.
import asyncio
import os
import asyncpg
import aiohttp
from dotenv import load_dotenv
load_dotenv()
DB_URL = os.getenv('POSTGRESQL_URL')
async def process_addresses(pool: asyncpg.Pool):
async with pool.acquire() as connection:
addresses = [record['address'] for record in await connection.fetch('SELECT * FROM Rawaccount LIMIT 1 OFFSET 7')]
async with aiohttp.ClientSession() as session:
for address in addresses:
proxy = "адрес прокси"
key = "ключ"
url = f"https://toncenter.com/api/v3/wallet?address={address}&api_key={key}"
async with session.get(url, proxy=proxy) as response:
connection = response.connection
print(response.status)
async def main():
pool = await asyncpg.create_pool(DB_URL)
get_info_task = asyncio.create_task(process_addresses(pool))
await asyncio.gather(get_info_task)
asyncio.run(main())
Это очень упрощенная версия, в самом проекте подобный код устроен сложнее.
С недавних пор, по непонятной для меня причине стала возникать следующая ошибка:
200
Fatal error on SSL transport
protocol: <asyncio.sslproto.SSLProtocol object at 0x73b76b092e90>
transport: <_SelectorSocketTransport closing fd=8>
Traceback (most recent call last):
File "/usr/lib/python3.10/asyncio/selector_events.py", line 924, in write
n = self._sock.send(data)
OSError: [Errno 9] Bad file descriptor
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.10/asyncio/sslproto.py", line 690, in _process_write_backlog
self._transport.write(chunk)
File "/usr/lib/python3.10/asyncio/selector_events.py", line 930, in write
self._fatal_error(exc, 'Fatal write error on socket transport')
File "/usr/lib/python3.10/asyncio/selector_events.py", line 725, in _fatal_error
self._force_close(exc)
File "/usr/lib/python3.10/asyncio/selector_events.py", line 737, in _force_close
self._loop.call_soon(self._call_connection_lost, exc)
File "/usr/lib/python3.10/asyncio/base_events.py", line 753, in call_soon
self._check_closed()
File "/usr/lib/python3.10/asyncio/base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Fatal error on SSL transport
protocol: <asyncio.sslproto.SSLProtocol object at 0x73b76b092e30>
transport: <_SelectorSocketTransport closing fd=11>
Traceback (most recent call last):
File "/usr/lib/python3.10/asyncio/selector_events.py", line 924, in write
n = self._sock.send(data)
OSError: [Errno 9] Bad file descriptor
During handling of the above exception, another exception occurred:
# так еще несколько раз и в конце:
Traceback (most recent call last):
File "/usr/lib/python3.10/asyncio/sslproto.py", line 690, in _process_write_backlog
self._transport.write(chunk)
File "/usr/lib/python3.10/asyncio/selector_events.py", line 930, in write
self._fatal_error(exc, 'Fatal write error on socket transport')
File "/usr/lib/python3.10/asyncio/selector_events.py", line 725, in _fatal_error
self._force_close(exc)
File "/usr/lib/python3.10/asyncio/selector_events.py", line 737, in _force_close
self._loop.call_soon(self._call_connection_lost, exc)
File "/usr/lib/python3.10/asyncio/base_events.py", line 753, in call_soon
self._check_closed()
File "/usr/lib/python3.10/asyncio/base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Я погуглил и нашел
обсуждение подобной ошибки.
Там в качестве решения предложили использовать
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Вместо
asyncio.run(main())
.
И теперь действительно ошибка ушла и я в выводе просто вижу
200
, как и должно быть.
Первый возникший вопрос -
почему появляется ошибка? Второй -
почему изменение способа вызова событийного цикла устраняет эту ошибку?
upd:
В процессе написания этого вопроса я понял причину возникновения этой ошибки - я не закрываю пул соединений с БД.
Т.е. сейчас я добавил в конце
main()
строку
await pool.close()
и даже с вызовом
asyncio.run(main())
ошибка перестала возникать.
Тем не менее, я все равно до конца не понял, что точно означает эта ошибка и почему изменение вызова цикла ее исправляет.