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

如何让discord.py机器人仅在首次启动时调用指定函数

解决Discord.py机器人仅首次启动执行指定函数的问题

问题分析

你通过on_ready()事件触发restock()函数,但机器人离线重登(或脚本重启)时,on_ready()会重复触发,导致restock()被多次执行。尝试用全局变量控制但无效,核心原因有两点:

  1. 脚本重启后全局变量会被重置
  2. 代码中未正确声明全局变量,导致修改的是局部变量而非全局变量

修复步骤与解决方案

1. 针对脚本未重启的重连场景

如果只是机器人与Discord的连接断开后重连(脚本本身未重启),可以通过正确使用全局变量来控制:

# 初始化全局变量
restockkk = False

@bot.event
async def on_ready():
    global restockkk
    logchannel = bot.get_channel(ID_CHANNEL)
    await logchannel.send(f'Logged in as {bot.user}')
    await bot.change_presence(activity=discord.Game(name="Buddy is busy being the GOAT"))
    # 仅在未启动过restock时执行
    if not restockkk:
        await restock()

async def restock():
    global restockkk
    logchannel = bot.get_channel(960147355691253800)
    await logchannel.send('Restock monitor on')
    # 修改全局变量
    restockkk = True
    while True:
        try:
            if not restockkk:
                await bot.change_presence(activity=discord.Game(name="Buddy is busy being the GOAT"))
                break
            # ... 你的业务代码
            await asyncio.sleep(120)
            # ... 你的业务代码
            await asyncio.sleep(120)
        except Exception as e:
            await logchannel.send(f'exception occurred: {str(e)}')
            # 不要递归调用restock,改用continue避免栈溢出
            continue

@bot.command(pass_context=True)
async def stop(message):
    global restockkk
    if message.author.id == myId:
        restockkk = False
        await message.channel.send('Restock monitor is off')
    else:
        await message.channel.send('You are not allowed to use this command')

2. 针对脚本重启的场景(永久标记首次启动)

如果机器人因崩溃等原因导致脚本完全重启,全局变量会失效,此时需要用本地文件来标记是否已执行过首次启动:

import os

# 标记文件路径,用于记录是否已完成首次启动
STARTUP_MARKER = ".first_start_done"

@bot.event
async def on_ready():
    logchannel = bot.get_channel(ID_CHANNEL)
    await logchannel.send(f'Logged in as {bot.user}')
    await bot.change_presence(activity=discord.Game(name="Buddy is busy being the GOAT"))
    
    # 检查标记文件是否存在,不存在则执行首次启动逻辑
    if not os.path.exists(STARTUP_MARKER):
        await restock()
        # 创建标记文件,标记首次启动已完成
        with open(STARTUP_MARKER, 'w') as f:
            f.write("1")

async def restock():
    logchannel = bot.get_channel(960147355691253800)
    await logchannel.send('Restock monitor on')
    while True:
        try:
            # ... 你的业务代码
            await asyncio.sleep(120)
            # ... 你的业务代码
            await asyncio.sleep(120)
        except Exception as e:
            await logchannel.send(f'exception occurred: {str(e)}')
            continue

@bot.command(pass_context=True)
async def stop(message):
    global restockkk
    if message.author.id == myId:
        restockkk = False
        await message.channel.send('Restock monitor is off')
        # 如果需要下次启动重新执行restock,可删除标记文件
        # os.remove(STARTUP_MARKER)
    else:
        await message.channel.send('You are not allowed to use this command')

注意事项

  • 不要在restock()的异常处理中递归调用自身,否则会导致栈溢出,改用continue重新进入循环
  • 使用文件标记时,需确保机器人有读写该文件的权限
  • 若执行stop命令后希望下次启动重新执行restock(),可在stop命令逻辑中删除标记文件

内容的提问来源于stack exchange,提问作者maurijn.vd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:40:20