Rate limits
Every account has a bucket per action. A bucket holds burst requests, and refills at its rate, in requests a second. A request
that finds its bucket empty is refused with RATE_LIMITED before anything is done. A bot is an account, so it has buckets of
its own, separate from its owner's.
What the library does about it
illest.py keeps the same buckets on its side and waits for a token before it sends, so a bot that sends in a loop is slowed, not refused. The two can still disagree (another copy of the bot running on the same account, or a restart with full buckets on the bot's side and empty ones on the server's). A refused request is sent again after the time its bucket needs, three times, and only then raised:
import illest
async def announce(channel: illest.TextChannel, text: str):
try:
await channel.send(text)
except illest.RateLimited as error:
print(f"try again in {error.retry_after} seconds")retry_after is the server's figure when it gave one, otherwise the action's published rate.
The limits
Every action a bot may send, with its bucket. An action without a limit of its own takes the default, 10 at once, then 2 a second. The library is built against these numbers; a server that changes them is waited out by the retry.
| Action | At once | Then, a second |
|---|---|---|
auth.credential | 10 | 1 |
auth.device.list | 10 | 2 |
auth.device.rename | 10 | 2 |
auth.device.revoke | 10 | 2 |
auth.login.begin | 5 | 1 |
auth.login.complete | 5 | 1 |
auth.login.verify | 5 | 1 |
auth.logout | 10 | 2 |
auth.recover.begin | 5 | 1 |
auth.recover.complete | 3 | 0.5 |
auth.recover.verify | 3 | 0.2 |
auth.register.begin | 3 | 0.2 |
auth.register.cancel | 10 | 2 |
auth.register.complete | 5 | 1 |
auth.register.work | 5 | 0.5 |
auth.release | 5 | 0.5 |
auth.reset.begin | 5 | 1 |
auth.reset.complete | 3 | 0.2 |
auth.session.revoke_all | 10 | 2 |
auth.unpark | 5 | 0.5 |
badge.list | 10 | 2 |
bot.commands.get | 20 | 2 |
bot.commands.set | 5 | 0.5 |
bot.identify | 10 | 1 |
bot.identity.publish | 5 | 1 |
bot.info | 20 | 2 |
channel.devices | 40 | 8 |
channel.disappear.set | 60 | 10 |
channel.dm.open | 10 | 1 |
channel.get | 40 | 8 |
channel.group.leave | 60 | 10 |
channel.hide | 10 | 2 |
channel.list | 10 | 2 |
channel.messages.clear | 10 | 2 |
channel.messages.list | 40 | 8 |
channel.messages.purge | 30 | 10 |
channel.pins.list | 10 | 2 |
channel.read | 10 | 2 |
channel.topic.set | 10 | 2 |
channel.typing | 10 | 6 |
channel.unread | 10 | 2 |
commands.index | 20 | 2 |
friend.accept | 10 | 2 |
friend.block | 10 | 2 |
friend.blocked | 10 | 2 |
friend.list | 10 | 2 |
friend.reject | 10 | 2 |
friend.remove | 10 | 2 |
friend.request | 10 | 0.5 |
friend.unblock | 10 | 2 |
guild.application.decide | 10 | 2 |
guild.application.form.get | 10 | 2 |
guild.application.get | 10 | 2 |
guild.application.list | 10 | 2 |
guild.audit | 10 | 4 |
guild.automod.event.settle | 20 | 5 |
guild.automod.events | 10 | 2 |
guild.automod.get | 20 | 2 |
guild.automod.lockdown | 5 | 1 |
guild.automod.raid.remove | 5 | 1 |
guild.ban | 10 | 2 |
guild.bans | 10 | 2 |
guild.boosts | 10 | 2 |
guild.category.create | 10 | 2 |
guild.category.delete | 10 | 2 |
guild.category.permissions | 10 | 2 |
guild.category.permissions.set | 10 | 2 |
guild.category.reorder | 10 | 2 |
guild.category.update | 10 | 2 |
guild.channel.create | 10 | 2 |
guild.channel.delete | 10 | 2 |
guild.channel.follow | 5 | 0.5 |
guild.channel.lock | 10 | 2 |
guild.channel.permissions | 10 | 2 |
guild.channel.permissions.set | 10 | 2 |
guild.channel.published | 5 | 1 |
guild.channel.reorder | 10 | 2 |
guild.channel.unfollow | 5 | 0.5 |
guild.channel.update | 10 | 2 |
guild.counter.add | 5 | 0.5 |
guild.counter.remove | 5 | 0.5 |
guild.counter.set | 5 | 1 |
guild.expression.create | 10 | 2 |
guild.expression.delete | 10 | 2 |
guild.expression.list | 10 | 2 |
guild.expression.update | 10 | 2 |
guild.follows.list | 5 | 1 |
guild.get | 10 | 2 |
guild.giveaway.cancel | 5 | 0.5 |
guild.giveaway.end | 5 | 0.5 |
guild.giveaway.list | 5 | 1 |
guild.giveaway.reroll | 5 | 0.5 |
guild.giveaway.start | 5 | 0.2 |
guild.invite.create | 20 | 2 |
guild.invite.list | 10 | 2 |
guild.invite.preview | 20 | 3 |
guild.invite.revoke | 10 | 2 |
guild.invites.joins | 5 | 1 |
guild.join | 30 | 2 |
guild.kick | 10 | 2 |
guild.leave | 10 | 2 |
guild.levels.get | 10 | 2 |
guild.levels.list | 5 | 1 |
guild.levels.reset | 10 | 2 |
guild.line.delete | 30 | 5 |
guild.lines.list | 5 | 1 |
guild.list | 10 | 2 |
guild.members | 15 | 3 |
guild.message.publish | 10 | 1 |
guild.message.unpublish | 10 | 1 |
guild.onboarding.get | 10 | 2 |
guild.onboarding.preview | 20 | 3 |
guild.overrides | 10 | 4 |
guild.overrides.all | 6 | 2 |
guild.profile.get | 15 | 3 |
guild.profile.set | 10 | 2 |
guild.role.assign | 10 | 2 |
guild.role.create | 10 | 2 |
guild.role.delete | 10 | 2 |
guild.role.reorder | 10 | 2 |
guild.role.update | 10 | 2 |
guild.rules.get | 10 | 2 |
guild.rules.let_in | 10 | 2 |
guild.rules.set | 10 | 2 |
guild.timeout | 10 | 2 |
guild.unban | 10 | 2 |
guild.vanity.resolve | 30 | 3 |
guild.warn | 30 | 5 |
guild.warning.delete | 30 | 5 |
guild.warnings | 15 | 3 |
identity.certify | 5 | 1 |
identity.get | 10 | 2 |
identity.publish | 5 | 1 |
link.preview | 10 | 0.5 |
media.fetch | 20 | 1 |
media.ticket | 10 | 1 |
message.pin | 30 | 10 |
message.redact | 30 | 10 |
message.send | 20 | 5 |
message.unpin | 30 | 10 |
mls.commit.submit | 20 | 5 |
mls.commits.since | 60 | 12 |
mls.grant.clear | 5 | 1 |
mls.grant.issue | 20 | 5 |
mls.grant.needed | 60 | 12 |
mls.group.reset | 2 | 0.2 |
mls.group.roster | 10 | 2 |
mls.group_info.get | 10 | 2 |
mls.group_info.publish | 20 | 5 |
mls.key_packages.claim | 30 | 6 |
mls.key_packages.count | 10 | 2 |
mls.key_packages.publish | 5 | 1 |
mls.key_packages.purge | 5 | 1 |
mls.welcomes.ack | 10 | 2 |
mls.welcomes.pending | 10 | 2 |
name.available | 20 | 2 |
name.resolve | 20 | 2 |
pins.get | 20 | 2 |
pins.put | 10 | 0.5 |
presence.set | 5 | 1 |
user.get | 20 | 4 |
user.update | 10 | 2 |
voice.member.deafen | 12 | 4 |
voice.member.disconnect | 12 | 4 |
voice.member.move | 12 | 4 |
voice.member.mute | 12 | 4 |
voice.states | 10 | 2 |
Being a good citizen
- Send one message with several lines rather than several messages.
- Edit a status message rather than posting a new one each minute.
- A task that runs on a timer (
ext.tasks.loop) should run as often as its answer changes, and no more.