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

使用Async SQLAlchemy的Discord Bot退出时触发RuntimeError问题

解决Discord Bot异步SQLAlchemy退出时的Event Loop Closed错误

针对你遇到的RuntimeError: Event loop is closed错误(溯源至aiomysql的Connection.__del__方法),以下是具体解决方向和文档理解确认:

核心问题本质

错误出在事件循环已经关闭后,aiomysql的连接对象被垃圾回收(GC)触发__del__方法,试图在已关闭的循环中执行异步操作。根源是数据库连接/连接池没有在事件循环关闭前被正确释放。

具体解决方向

1. 显式优先关闭数据库连接池

不要依赖Discord的on_disconnect事件处理数据库关闭(该事件触发时循环可能已进入关闭阶段),而是在Bot关闭流程之前主动释放数据库资源:

  • 使用asyncio.run包裹Bot启动逻辑,在finally块中显式调用SQLAlchemy异步引擎的dispose()方法:
    import asyncio
    from discord.ext import commands
    from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
    from sqlalchemy.orm import sessionmaker
    
    engine = create_async_engine("mysql+aiomysql://user:pass@host/db")
    async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)
    bot = commands.Bot(command_prefix="!", intents=...)
    
    async def main():
        try:
            await bot.start("YOUR_BOT_TOKEN")
        finally:
            # 先关闭数据库连接池,释放所有连接
            await engine.dispose()
    
    asyncio.run(main())
    
  • 这样能确保所有数据库连接在事件循环关闭前被正确回收,避免GC触发__del__时循环已不可用。

2. 严格使用上下文管理器管理数据库会话

检查代码中是否存在未正确释放的数据库会话/连接,比如没有用async with包裹会话:

  • 所有数据库操作必须遵循异步会话的规范写法:
    async def some_db_operation():
        async with async_session() as session:
            async with session.begin():
                # 执行数据库读写操作
    
    这种写法会自动关闭会话并将连接归还到池,避免残留的连接对象被GC延迟处理。

3. 调整事件循环的管理顺序

如果手动管理事件循环(而非用asyncio.run),必须确保数据库资源释放先于循环关闭:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
    loop.run_until_complete(bot.start("YOUR_BOT_TOKEN"))
finally:
    # 先处理数据库关闭
    loop.run_until_complete(engine.dispose())
    # 再关闭事件循环
    loop.close()

4. 检查依赖版本兼容性

确保使用最新稳定版的SQLAlchemy(2.0+)和aiomysql,旧版本可能存在异步连接池资源泄漏的bug,导致连接无法被正确回收。

文档理解确认

你之前的问题确实存在对文档的误解:

  • SQLAlchemy异步文档明确要求:异步引擎必须显式调用dispose()来关闭连接池、释放所有底层连接,不能依赖垃圾回收自动处理异步资源。
  • Discord.py的on_disconnect事件并非用于清理异步资源的合适时机——该事件触发时,Bot的事件循环可能已经进入关闭流程,此时执行异步操作(如数据库关闭)会因循环不可用而失败。正确的资源清理应放在Bot启动逻辑的finally块,或使用Discord.py的before_close事件(在Bot开始关闭流程前触发)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 13:51:13