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

迁移至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()会自动释放连接。

修复步骤

  1. 将连接池作为机器人实例的属性,在setup_hook中初始化(这是discord.py v2推荐的异步资源初始化入口)。
  2. 移除手动获取事件循环的代码,完全依赖discord.py的内置循环。
  3. 删除命令中多余的连接关闭操作。

修改后的代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 01:10:27