Discord.py报错'Unclosed client session',周期性调用函数失败
问题分析
你遇到的Unclosed client session错误,核心原因是全局的Discord Client实例被重复启动。第一次调用getMessage()时,客户端启动、执行任务后关闭,但这个实例已经处于不可复用的状态,第二次再调用client.start()就会因为会话未正确清理或实例已失效而报错。
解决方案
方案一:保持客户端长期运行(推荐)
Discord机器人的设计初衷是长期在线,周期性任务应该在客户端运行时通过异步任务调度实现,而不是反复启停客户端。这种方式更高效,也避免了实例复用的问题。
修改posterbot.py:
import discord import asyncio import main intents = discord.Intents.default() intents.message_content = True client = discord.Client(intents=intents) CHECK_INTERVAL = 10 # 任务间隔时间(秒) async def fetch_first_message(): guild_id = 1177834521274626118 channel_id = 1177834521274626121 guild = client.get_guild(guild_id) if not guild: print("无法找到目标服务器") return channel = guild.get_channel(channel_id) if not channel: print("无法找到目标频道") return async for message in channel.history(limit=1, oldest_first=True): main.handleMessage(message.content) print(f'Earliest message: {message.content}') break async def periodic_task(): await client.wait_until_ready() # 等待客户端完成登录 while not client.is_closed(): await fetch_first_message() await asyncio.sleep(CHECK_INTERVAL) @client.event async def on_ready(): print(f'Logged in as {client.user.name}') # 启动周期性任务 asyncio.create_task(periodic_task()) def start_bot(): loop = asyncio.get_event_loop() loop.run_until_complete(client.start(apikey))
修改main.py:
import posterbot if __name__ == '__main__': posterbot.start_bot() def handleMessage(message): pass
方案二:每次调用创建新Client实例
如果必须每次任务都启停客户端,需要在每次调用时创建新的Client实例,而不是复用全局实例:
修改posterbot.py:
import discord import asyncio import main async def fetch_first_message(client): guild_id = 1177834521274626118 channel_id = 1177834521274626121 guild = client.get_guild(guild_id) if not guild: print("无法找到目标服务器") return channel = guild.get_channel(channel_id) if not channel: print("无法找到目标频道") return async for message in channel.history(limit=1, oldest_first=True): main.handleMessage(message.content) print(f'Earliest message: {message.content}') break async def run_single_fetch(): intents = discord.Intents.default() intents.message_content = True client = discord.Client(intents=intents) @client.event async def on_ready(): print(f'Logged in as {client.user.name}') await fetch_first_message(client) await client.close() await client.start(apikey) def getMessage(): loop = asyncio.new_event_loop() # 创建新事件循环,避免旧循环状态干扰 asyncio.set_event_loop(loop) loop.run_until_complete(run_single_fetch()) loop.close()
main.py保持原有代码即可。
关键说明
- 方案一符合Discord机器人的运行逻辑,减少登录次数,还能避免频繁登录触发平台风控,是更优选择。
- 方案二仅适合单次任务场景,频繁启停客户端效率低,不推荐长期使用。
内容的提问来源于stack exchange,提问作者Ian Weed
相关产品推荐
相关产品推荐

