discord.py中on_ready调用change_presence限流及sleep有效性咨询
结论
你在on_ready开头加asyncio.sleep(5)的写法确实能缓解启动阶段的瞬时请求冲突,但没有完全消除速率限制风险。
核心问题本质
很多人对这个场景的风险来源有误解:在on_ready里调用change_presence容易触发速率限制,根本原因不是启动阶段初始化API调用太多挤占配额,而是on_ready本身的触发机制——它不是机器人启动完成后只执行1次的事件,机器人长时运行过程中和Discord网关断连重连是非常普遍的情况,每次重连都会重新触发一次on_ready。如果不加判断,每次重连都自动执行一次改状态的请求,短时间内重连次数多了,重复的API请求攒到Discord的速率阈值,轻则接口报错,重则触发临时限制甚至长期封禁。
现有方案的有效性
- 5秒等待的逻辑是有实际作用的:机器人刚连接网关的阶段会集中拉取所在服务器、频道、成员等缓存数据,请求密度很高,等5秒再发自定义请求能错开这个峰值,降低刚启动就撞瞬时速率限制的概率。
- 但这个写法没有解决核心隐患:只要发生重连,
on_ready会再次触发,等待5秒后又会发送一次改状态的请求,重连频繁的时候照样会触发速率限制,和不加等待的写法相比只是降低了启动瞬间的风险,长期运行的隐患完全没有消除。
修正后的安全写法
要彻底规避风险非常简单,加一个布尔标记位,保证改状态的逻辑在机器人整个运行周期只执行一次即可,参考代码:
from discord.ext import commands import discord import asyncio class YourCog(commands.Cog): def __init__(self, bot): self.bot = bot # 标记位:记录是否已经完成过状态设置 self.presence_set = False @commands.Cog.listener() async def on_ready(self): # 已经设置过状态就直接返回,不重复执行逻辑 if self.presence_set: return # 保留原有等待逻辑,错开启动请求峰值 await asyncio.sleep(5) await self.bot.change_presence( activity=discord.Activity( type=discord.ActivityType.watching, name="❌" ) ) # 标记为已设置,后续重连触发事件时不会重复调用接口 self.presence_set = True
补充说明:网上流传的「在
on_ready里改状态必被封」是不准确的。单次调用change_presence属于完全合规的常规API请求,本身不会触发任何处罚,所有相关的速率限制处罚本质都是短时间内无意义重复调用突破阈值导致的。只要做好单次执行的判断,哪怕去掉5秒等待逻辑,也基本不会出现相关问题。
内容的提问来源于stack exchange,提问作者c00kie
相关产品推荐
相关产品推荐

