迁移至discord.py 2.0时asyncpg无法正常工作求助
问题:迁移至discord.py v2版本时asyncpg无法正常工作
我正在把旧Discord机器人迁移到discord.py v2版本,但asyncpg一直无法正常工作,找不到原因。我试过把loop和pool放到on_ready和setup_hook里,还是解决不了问题。
我的代码如下:
import discord from discord import app_commands import aiohttp import asyncio import requests from discord.ext import commands import os import asyncpg # Pydest # Define Client class Aclient(commands.Bot): def __init__(self): super().__init__(command_prefix='.', intents=discord.Intents.default()) self.synced = False async def setup_hook(self): cog = await self.load_extension('cogs.weather') print(f"Loaded All Cogs") if not self.synced: await self.tree.sync() self.synced = True async def on_ready(self): await self.wait_until_ready() if not self.synced: await self.tree.sync() self.synced = True await client.change_presence(status=discord.Status.dnd) print(f'We have logged in as {self.user}') client=Aclient() # test command @client.tree.command(name="test", description="testing") async def test(interaction: discord.Interaction, name: str): async with pool.acquire() as connection: async with connection.transaction(): check = await connection.fetchrow('select * from weather') print(check) await connection.close() loop = asyncio.get_event_loop() pool = loop.run_until_complete(asyncpg.create_pool(**credentials))
遇到的错误如下:
Traceback (most recent call last): File "/Users/prathik/Documents/GitHub/red/YELLOW/bot.py", line 61, in test async with connection.transaction(): File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/asyncpg/transaction.py", line 62, in __aenter__ await self.start() File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/asyncpg/transaction.py", line 138, in start await self._connection.execute(query) File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/asyncpg/connection.py", line 317, in execute return await self._protocol.query(query, timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "asyncpg/protocol/protocol.pyx", line 338, in query RuntimeError: Task <Task pending name='CommandTree-invoker' coro=<CommandTree._from_interaction.<locals>.wrapper() running at /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/discord/app_commands/tree.py:1089>> 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 "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/discord/app_commands/commands.py", line 851, in _do_call return await self._callback(interaction, **params) # type: ignore ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/prathik/Documents/GitHub/red/YELLOW/bot.py", line 60, in test async with pool.acquire() as connection: File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/asyncpg/pool.py", line 220, in release raise ex File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/asyncpg/pool.py", line 210, in release await self._con.reset(timeout=budget) File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/asyncpg/connection.py", line 1366, in reset await self.execute(reset_query, timeout=timeout) File "/Library/Frameworks/Python.framework/Versions/3.11/lib/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 The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/discord/app_commands/tree.py", line 1240, in _call await command._invoke_with_namespace(interaction, namespace) File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/discord/app_commands/commands.py", line 876, in _invoke_with_namespace return await self._do_call(interaction, transformed_values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/discord/app_commands/commands.py", line 869, in _do_call raise CommandInvokeError(self, e) from e discord.app_commands.errors.CommandInvokeError: Command 'test' raised an exception: InterfaceError: cannot perform operation: another operation is in progress
解答
问题根源
- 事件循环不匹配:你手动创建的asyncio事件循环和discord.py内部管理的循环不是同一个。discord.py v2会自动维护自己的事件循环,提前用
loop.run_until_complete()创建的连接池绑定到了外部循环,导致后续命令任务调用时出现循环不兼容的错误。 - 冗余操作:
test命令里手动调用await connection.close()完全多余,async with pool.acquire()会自动释放连接。
修复步骤
- 将连接池作为机器人实例的属性,在
setup_hook中初始化(这是discord.py v2推荐的异步资源初始化入口)。 - 移除手动获取事件循环的代码,完全依赖discord.py的内置循环。
- 删除命令中多余的连接关闭操作。
修改后的代码
import discord from discord import app_commands import aiohttp import asyncio import requests from discord.ext import commands import os import asyncpg # Define Client class Aclient(commands.Bot): def __init__(self): super().__init__(command_prefix='.', intents=discord.Intents.default()) self.synced = False self.pool = None # 初始化连接池属性 async def setup_hook(self): # 在setup_hook中初始化数据库连接池 self.pool = await asyncpg.create_pool(**credentials) await self.load_extension('cogs.weather') print(f"Loaded All Cogs") if not self.synced: await self.tree.sync() self.synced = True async def on_ready(self): await self.wait_until_ready() if not self.synced: await self.tree.sync() self.synced = True await self.change_presence(status=discord.Status.dnd) # 使用self代替全局client变量 print(f'We have logged in as {self.user}') client=Aclient() # test command @client.tree.command(name="test", description="testing") async def test(interaction: discord.Interaction, name: str): async with client.pool.acquire() as connection: # 简单查询无需手动开启事务,asyncpg会自动处理 check = await connection.fetchrow('select * from weather') print(check) # 无需手动关闭连接,async with会自动释放 # 启动机器人,由discord.py管理事件循环 client.run('你的机器人Token')
补充说明
- 确保
credentials是包含数据库连接信息的字典,格式示例:{'user': '你的用户名', 'password': '你的密码', 'database': '数据库名', 'host': 'localhost'}。 - 如果cogs中需要使用连接池,可以通过
self.bot.pool访问。
内容的提问来源于stack exchange,提问作者PRA7H1K
相关产品推荐
相关产品推荐

