You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在aiogram中正确使用asyncpg?连接池报错排查

aiogram + asyncpg 事件循环不匹配导致的InterfaceError问题解决

问题描述

基于aiogram框架开发Telegram Bot时,使用asyncpg库操作PostgreSQL数据库。数据库类初始化阶段通过asyncio.get_event_loop()同步执行create_pool创建连接池,程序启动时显示数据库连接成功,但首次发起数据库请求时抛出InterfaceError: cannot perform operation: another operation is in progress,同时伴随RuntimeError: Task got Future attached to a different loop的事件循环不匹配错误。

相关代码

数据库类代码

class DataBase:

    def __init__(self):
        self.db_pool = None
        loop = asyncio.get_event_loop()
        loop.run_until_complete(self.create_pool())

    async def create_pool(self):
        try:
            self.db_pool = await asyncpg.create_pool(Config.POSTGRES_URI)
            async with self.db_pool.acquire() as connection:
                await connection.execute('SELECT 1')
            print("\tSuccessful connection to the database")
        except Exception as e:
            print(f"\tDatabase connection error: {e}")

报错信息

Cause exception while process update id=56403182 by bot id=6663434503
InterfaceError: cannot perform operation: another operation is in progress
Traceback (most recent call last):
  File "beauty_experts_bot/src/services/sql.py", line 27, in add_user
    await connection.execute("""INSERT INTO user (id, username, name) VALUES (?, ?, ?)""",
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/connection.py", line 319, in execute
    _, status, _ = await self._execute(
                   ^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/connection.py", line 1659, in _execute
    result, _ = await self.__execute(
                ^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/connection.py", line 1684, in __execute
    return await self._do_execute(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/connection.py", line 1711, in _do_execute
    stmt = await self._get_statement(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/connection.py", line 397, in _get_statement
    statement = await self._protocol.prepare(
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "asyncpg/protocol/protocol.pyx", line 168, in prepare
RuntimeError: Task <Task pending name='Task-29' coro=<Dispatcher._process_update() running at /home/davyd/MY_DATA/programming/tmp_project/beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/dispatcher.py:308>> got Future <Future pending cb=[Protocol._on_waiter_completed()]> attached to a different loop

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/dispatcher.py", line 308, in _process_update
    response = await self.feed_update(bot, update, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/dispatcher.py", line 157, in feed_update
    response = await self.update.wrap_outer_middleware(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/middlewares/error.py", line 25, in __call__
    return await handler(event, data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/middlewares/user_context.py", line 27, in __call__
    return await handler(event, data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/fsm/middleware.py", line 39, in __call__
    return await handler(event, data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/event/telegram.py", line 120, in trigger
    return await wrapped_inner(event, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/event/handler.py", line 42, in call
    return await wrapped()
           ^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/dispatcher.py", line 275, in _listen_update
    return await self.propagate_event(update_type=update_type, event=event, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/router.py", line 116, in propagate_event
    return await observer.wrap_outer_middleware(_wrapped, event=event, data=kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/router.py", line 111, in _wrapped
    return await self._propagate_event(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/router.py", line 136, in _propagate_event
    response = await observer.trigger(event, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/event/telegram.py", line 120, in trigger
    return await wrapped_inner(event, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "beauty_experts_bot/venv/lib/python3.11/site-packages/aiogram/dispatcher/event/handler.py", line 42, in call
    return await wrapped()
           ^^^^^^^^^^^^^^^
  File "beauty_experts_bot/src/handlers/basic.py", line 15, in start
    await db.add_user(
  File "beauty_experts_bot/src/services/sql.py", line 26, in add_user
    async with self.db_pool.acquire() as connection:
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/pool.py", line 220, in release
    raise ex
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/pool.py", line 210, in release
    await self._con.reset(timeout=budget)
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/connection.py", line 1366, in reset
    await self.execute(reset_query, timeout=timeout)
  File "beauty_experts_bot/venv/lib64/python3.11/site-packages/asyncpg/connection.py", line 317, in execute
    return await self._protocol.query(query, timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "asyncpg/protocol/protocol.pyx", line 323, in query
  File "asyncpg/protocol/protocol.pyx", line 707, in asyncpg.protocol.protocol.BaseProtocol._check_state
asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress

数据库请求代码

db = DataBase()

async def start(message: Message) -> None:
    await db.add_user(
        user_id=message.from_user.id,
        username=message.from_user.username,
        name=message.from_user.full_name
    )

Bot启动代码

from aiogram import Bot, Dispatcher
import asyncio
from aiogram.enums.parse_mode import ParseMode

from config import Config
from handlers import basic, specialist, admin
from utils.commands import set_commands


async def start():
    bot = Bot(token=Config.TOKEN, parse_mode=ParseMode.HTML)
    dp = Dispatcher(bot=bot)

    # REGISTER HANDLERS
    basic.register_handlers(dp=dp)
    specialist.register_handlers(dp=dp)
    admin.register_handlers(dp=dp)

    await set_commands(bot=bot)

    try:
        await dp.start_polling(bot)
    finally:
        await bot.send_message(chat_id=Config.ADMIN_ID, text="<b>BOT STOPPED</b>")
        await bot.session.close()

if __name__ == "__main__":
    asyncio.run(start())

问题根源

核心问题是事件循环不匹配:

  • 当db = DataBase()执行时,__init__方法通过asyncio.get_event_loop()获取了当前主线程的事件循环,并在该循环中创建了数据库连接池。
  • 而asyncio.run(start())会创建一个全新的事件循环来运行Bot的异步逻辑,这个新循环和连接池所属的旧循环不是同一个对象。
  • 当Bot的处理任务(运行在新循环)尝试使用连接池时,就会出现"Future attached to a different loop"的错误,进而引发InterfaceError。

解决方案

1. 修改数据库类,改为异步初始化

去掉__init__中的同步创建逻辑,添加异步初始化方法:

class DataBase:
    def __init__(self):
        self.db_pool = None

    async def setup(self):
        try:
            self.db_pool = await asyncpg.create_pool(Config.POSTGRES_URI)
            async with self.db_pool.acquire() as connection:
                await connection.execute('SELECT 1')
            print("\tSuccessful connection to the database")
        except Exception as e:
            print(f"\tDatabase connection error: {e}")

2. 在Bot启动逻辑中异步初始化数据库

调整start函数,先初始化数据库再启动Bot:

# 全局只声明db对象,不立即初始化
db = DataBase()

async def start():
    bot = Bot(token=Config.TOKEN, parse_mode=ParseMode.HTML)
    dp = Dispatcher(bot=bot)

    # 先初始化数据库
    await db.setup()

    # REGISTER HANDLERS
    basic.register_handlers(dp=dp)
    specialist.register_handlers(dp=dp)
    admin.register_handlers(dp=dp)

    await set_commands(bot=bot)

    try:
        await dp.start_polling(bot)
    finally:
        await bot.send_message(chat_id=Config.ADMIN_ID, text="<b>BOT STOPPED</b>")
        await bot.session.close()
        # 关闭数据库连接池
        if db.db_pool:
            await db.db_pool.close()

if __name__ == "__main__":
    asyncio.run(start())

3. 修正SQL占位符(额外问题)

asyncpg使用$1, $2, $3作为占位符,而不是?,同时user是PostgreSQL保留字,需要用双引号包裹表名,修改add_user方法中的SQL语句:

async def add_user(self, user_id, username, name):
    async with self.db_pool.acquire() as connection:
        await connection.execute("""
            INSERT INTO "user" (id, username, name) VALUES ($1, $2, $3)
        """, user_id, username, name)

验证

修改完成后重新启动Bot,首次发起数据库请求时将不再出现事件循环不匹配的错误,数据库操作可以正常执行。

内容的提问来源于stack exchange,提问作者Maxwell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:30:57