Не удаётся подключится к боту и базе данных асинхронно

Пытаюсь соединить Aiogram3 и asyncpg, но столкнулся с недостатком понимания асинхронности.

Я пытался сделать запуск БД и бота таким образом:

dp = Dispatcher()
adb = DB(DSN)


@dp.message(CommandStart)
async def start(message: Message):
    async with adb.pool.acquire() as conn: # взять подключение из пула и потом вернуть обратно;
        x = await conn.fetch('SELECT * FROM manga;')
    print(x)
    await message.answer('Работает.')


async def main():
    bot = Bot(token=TOKEN)

    await adb.connect()
    await dp.start_polling(bot)

if __name__ == '__main__':
    asyncio.run(main())
class DB:
    def __init__(self, dsn):
        self.dsn = dsn
        self.pool = None

    async def connect(self):
        self.pool = await asyncpg.create_pool(self.dsn) # создать пулл подключений;

    async def close(self):
        await self.pool.close()

Но я понял, что асинхронностю тут и не пахнет, две корутины блокируют друг друга и работают последовательно, а не асинхронно.

Я в принципе не нашёл достойных примеров применения asyncpg, хотя вроде как эта библиотека вне конкуренции по скорости среди всех подобных, так как использует не текстовые инструкции, а обращение к байт коду через C.

Если есть какие-нибудь best practices, я буду очень рад почитать.


Ответы (2 шт):

Автор решения: mrBars1k

Проблема решена созданием задач:

async def main():
    bot = Bot(token=TOKEN)

    task1 = asyncio.create_task(adb.connect())
    task2 = asyncio.create_task(dp.start_polling(bot))

    await task1 
    await task2

if __name__ == '__main__':
    asyncio.run(main())

Также, используя gather, удалось сделать то же самое, но короче и проще.

async def main():
    bot = Bot(token=TOKEN)

    task1 = asyncio.create_task(adb.connect())
    task2 = asyncio.create_task(dp.start_polling(bot))

    await asyncio.gather(task1, task2)

if __name__ == '__main__':
    asyncio.run(main())

Но даже с таким подходом иногда возникали ошибки, что нет такого метода .acquire(), потому что БД не успевало создать пулл подключений, когда бот уже запускался. Или вроде того.

→ Ссылка
Автор решения: Ben Puls

Возможно такой способ поможет решить проблему. За основу я взял ваш код, поэтому класс будет таким же.

class DB:

    def __init__(self, dsn):
        self.dsn = dsn
        self.pool = None

    async def get_connection(self):
        return self.pool

    async def connect(self):
        self.pool = await asyncpg.create_pool(self.dsn)
            
    async def close(self):
        await self.pool.close()

Указываем параметры подключения, в нашем случае dns postgres://user:password@host:port/database.

db = DB("postgres://user:password@host:port/database")

Из переменной db обращаемся к методу connect(), для того чтобы создать пул, а затем обращаемся к get_connection(), чтобы получить пул. А затем можем работать с базой данных.

async def main():
    await db.connect()

    pool = await db.get_connection()

    async with pool.acquire() as conn:
        print(await conn.fetchrow("""SELECT * FROM users"""))


asyncio.run(main())
→ Ссылка