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

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)
解决方案

核心问题分析

你的代码存在两个关键问题导致按钮反复超时:

  1. View默认超时限制:Discord.py的View默认timeout=180秒(3分钟),即使每小时重新绑定,中间的27分钟按钮都会处于失效状态。
  2. 嵌套回调的闭包风险:在循环任务内部定义回调函数,可能导致变量引用异常,影响按钮逻辑执行。

优化方案

改用自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 20:47:14