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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:13:37