Discord.py按钮超时问题:重复初始化仍多次失效
问题描述
我开发了一个带嵌入消息(Embed)按钮的Python Discord机器人。发现仅初始化一次按钮会出现超时问题,于是设置每小时循环重新将按钮绑定到嵌入消息,但经过几次迭代后按钮仍然会超时。
相关代码
import numpy as np import discord from discord.ext import tasks, commands import sqlite3 import random import datetime import GlobalEx as BKED from discord import app_commands from datetime import date from discord.ui import Button, View import json import Embeds as EMCB from Logger import LogCSV from ast import literal_eval import time @tasks.loop(seconds=60*60) async def EmbedChecks(self): b1 = Button(label="Enter", style=discord.ButtonStyle.green, custom_id=f"{a[2]}|giveawayenter") b2 = Button(label="Leave", style=discord.ButtonStyle.red, custom_id=f"{a[2]}|giveawayexit") b3 = Button(label="Get Roles",style=discord.ButtonStyle.url,url="https://patreon.com/AfterHours_OFFL") async def button_callback(interaction: discord.Interaction): # Some button stuff here which works b1.callback = button_callback b2.callback = button_callback view = View() view.add_item(b1) view.add_item(b2) view.add_item(b3) channel = self.bot.get_channel(a[3]) msg = await channel.fetch_message(a[2]) await msg.edit(view=view)
解决方案
核心问题分析
你的代码存在两个关键问题导致按钮反复超时:
- View默认超时限制:Discord.py的
View默认timeout=180秒(3分钟),即使每小时重新绑定,中间的27分钟按钮都会处于失效状态。 - 嵌套回调的闭包风险:在循环任务内部定义回调函数,可能导致变量引用异常,影响按钮逻辑执行。
优化方案
改用自定义View类并设置永久超时,彻底解决按钮失效问题,同时避免循环刷新的冗余操作:
1. 创建自定义永久有效View
class GiveawayView(View): def __init__(self, giveaway_id): super().__init__(timeout=None) # 设置为None,让View永久有效 self.giveaway_id = giveaway_id # 存储抽奖ID,用于后续逻辑处理 # Enter按钮回调 @discord.ui.button(label="Enter", style=discord.ButtonStyle.green, custom_id="giveaway_enter") async def enter_callback(self, interaction: discord.Interaction, button: Button): # 这里写你的Enter按钮逻辑,比如根据self.giveaway_id操作数据库 await interaction.response.send_message("已成功参与抽奖!", ephemeral=True) # Leave按钮回调 @discord.ui.button(label="Leave", style=discord.ButtonStyle.red, custom_id="giveaway_leave") async def leave_callback(self, interaction: discord.Interaction, button: Button): # 这里写你的Leave按钮逻辑 await interaction.response.send_message("已退出本次抽奖!", ephemeral=True)
2. 初始化嵌入消息时绑定View
在发送或编辑嵌入消息时,直接使用这个自定义View,同时添加URL按钮:
# 假设a是从数据库获取的抽奖数据(抽奖ID、频道ID等) giveaway_id = a[2] channel_id = a[3] # 创建自定义View view = GiveawayView(giveaway_id) # 添加URL按钮 url_button = Button(label="Get Roles", style=discord.ButtonStyle.url, url="https://patreon.com/AfterHours_OFFL") view.add_item(url_button) # 获取频道并编辑消息(或发送新消息) channel = self.bot.get_channel(channel_id) msg = await channel.fetch_message(giveaway_id) await msg.edit(view=view)
3. 移除定时刷新任务
因为已经设置View永久有效,不再需要EmbedChecks定时任务,直接删除即可。
额外注意事项
- 确保机器人启动时,通过
bot.add_view(GiveawayView(giveaway_id))注册所有已存在的抽奖View,避免机器人重启后按钮失效。 - 如果抽奖有结束时间,可以在结束时调用
view.stop()手动终止View,释放资源。
内容的提问来源于stack exchange,提问作者Yen
相关产品推荐
相关产品推荐

