Pycord开发的Discord Bot频繁离线停止响应问题排查
Pycord Bot自定义启动后频繁离线的排查方案
问题本质
你的情况核心是自定义启动逻辑缺失了bot.run()内置的连接维持、心跳管理和自动重连机制。用bot.run()时正常,说明Bot本身的业务逻辑没问题,问题出在main()协程对事件循环、连接生命周期的处理上。每10分钟触发on_ready()但on_connect()不触发,是因为Discord网关判定连接超时后被动触发重连,而非Bot主动发起的新连接。
重点排查方向
1. 事件循环管理错误
自定义启动时如果手动处理事件循环却没让它持续运行,或者某个任务结束后意外终止了循环,会导致Pycord无法维持心跳,Discord网关断开连接后只能被动等待重连。
- 检查
main()里是否用asyncio.run()正确托管整个流程,不要手动调用loop.stop()之类的方法提前终止循环。 - 确保所有异步任务(包括Bot启动、数据库操作)都绑定到同一个事件循环,不要混用多个循环实例。
2. asyncpg与事件循环的冲突
你最初遇到的"Task is already in progress"错误,本质是asyncpg的连接池和Pycord的事件循环没有共享资源。自定义启动时如果先初始化asyncpg再启动Bot,或者反过来,要确保两者使用同一个循环:
async def main(): # 先初始化数据库连接池,绑定到当前循环 bot.db_pool = await asyncpg.create_pool(user="user", password="pass", database="db") try: # 启动Bot,自动复用当前事件循环 await bot.start("YOUR_BOT_TOKEN") finally: # 确保Bot退出时关闭数据库连接池 await bot.db_pool.close() if __name__ == "__main__": asyncio.run(main())
3. 缺失重连异常处理
bot.run()内部会自动捕获连接断开、心跳超时等异常并发起重连,自定义启动时如果只调用await bot.start(),遇到网络波动或网关断开时Bot会直接停止,只能等待Discord的被动重连(间隔约10分钟)。要手动添加异常捕获和重连逻辑:
async def main(): bot.db_pool = await asyncpg.create_pool(...) try: await bot.start("YOUR_BOT_TOKEN") except (discord.ConnectionClosed, asyncio.TimeoutError, asyncio.CancelledError) as e: print(f"连接异常,尝试重连: {str(e)}") # 可以添加重连次数限制,避免无限递归 await main() finally: await bot.db_pool.close()
4. 事件循环被阻塞
如果有耗时的数据库查询或同步操作阻塞了事件循环,Pycord无法按时发送心跳,会被Discord网关判定为超时断开。
- 检查所有任务,替换
time.sleep()为asyncio.sleep(),避免同步阻塞。 - 耗时的数据库操作或同步代码,放到线程池中执行:
from concurrent.futures import ThreadPoolExecutor async def heavy_db_operation(): def sync_task(): # 耗时的同步数据库操作 return bot.db_pool.fetch("SELECT * FROM large_table") loop = asyncio.get_running_loop() result = await loop.run_in_executor(ThreadPoolExecutor(), sync_task) return result
调试技巧
开启Pycord的调试日志,能直接看到网关连接、心跳、断开的详细信息,快速定位问题:
import logging logging.basicConfig(level=logging.DEBUG)
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

