
Discord.py 的 View 在长时间超时(如24小时)下不触发 on_timeout(),通常并非代码问题,而是因进程重启导致视图实例丢失;AWS 免费层等不稳定环境易引发此现象。
discord.py 的 view 在长时间超时(如24小时)下不触发 `on_timeout()`,通常并非代码问题,而是因进程重启导致视图实例丢失;aws 免费层等不稳定环境易引发此现象。
在 Discord.py 中,View.on_timeout() 是一个内存级回调方法:它仅在当前 Python 进程中、对应 View 实例存活的前提下被自动调用。一旦 bot 进程意外退出、崩溃、被系统回收(如 AWS EC2 免费实例休眠或内存溢出重启),所有未销毁的 View 对象都会从内存中彻底消失——此时即使原定超时时间未到,on_timeout() 也永远无法执行。
例如,以下代码逻辑正确,但无法保证长期可靠运行:
class MyView(discord.ui.View):
def __init__(self):
super().__init__(timeout=24*60*60) # 24 小时
async def on_timeout(self):
print("TIMEOUT —— 但此行可能永远不会执行!")
# 此处本应更新消息、禁用按钮等,但若 bot 已重启则失效
✅ 根本原因不是 WebSocket 错误本身:WebSocket closed with 1000 表明连接正常关闭,常发生在进程优雅退出或被强制终止时;真正的问题是 View 生命周期完全依赖于单次 bot 运行周期,不具备跨进程持久性。
? 可行的缓解与替代方案:
-
避免超长 timeout:将
timeout设为较短值(如 5–30 分钟),配合「主动刷新」机制(如用户交互后重置 View); - 使用外部状态存储:借助数据库(SQLite/PostgreSQL)或缓存(Redis)记录 View 关联的消息 ID、创建时间、预期过期时间,在 bot 启动时扫描并手动执行超时逻辑;
-
启用
persistent=True+ 自定义custom_id:仅适用于Button/Select等可持久化组件(需搭配@discord.ui.button(..., custom_id="...")和bot.add_view()),但注意:on_timeout()依然不会被调用,你仍需自行实现超时清理; -
监控与告警:在 AWS 上启用 CloudWatch 日志监控
ConnectionClosed或异常退出,及时发现非预期重启。
? 重要提醒:
Discord 官方明确指出,View 不支持跨重启持久化。任何依赖 on_timeout() 处理关键业务逻辑(如解锁权限、释放资源、扣减库存)的场景,都必须引入外部持久化+定时任务(如 APScheduler 或云函数轮询)来兜底。
简言之:on_timeout() 是便利工具,不是可靠性保障;高可用 bot 必须将“超时”视为一种需主动管理的状态,而非被动等待的事件。










