-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Context
@yonilerner closed #5144 because he was "not sure exactly what [that] issue was about". This is only significant due to his request in closing, which would prevent necessary information - required to finalize and complete that issue - from being clarified. In other words, please do NOT close issues that you have not participated in.
This issue is a follow-up to #5144: For context, #5144 aims to give the documentation maintainers enough information to clarify the rate limit algorithm — in a pull request — that the Discord API implements and requires Discord Bots to adhere to. Unfortunately, multiple libraries are implementing these limits in a sub-par or incorrect manner due to the current documentation of the specification; among other factors.
As a solution, #5144 contains a number of discoveries that can be used to clarify the rate limit algorithm. This will allow these API Users to correctly implement rate limiting in their Discord Bots. However, there is one more obstacle (per-resource rate limits) that is documented in an ambigious manner. As a result, the easiest way to solve this issue is by clarifying the ambiguity.
Issue
The following excerpt is quoted from the Discord API Documentation Rate Limits page.
During calculation, per-route rate limits often account for top-level resources within the path using an identifier—for example, guild_id when calling /guilds/{guild.id}/channels. Top-level resources are currently limited to channels (channel_id), guilds (guild_id), and webhooks (webhook_id or webhook_id + webhook_token). This means that an endpoint with two different top-level resources may calculate limits independently. As an example, if you exceeded a rate limit when calling one endpoint /channels/1234, you could still call another similar endpoint like /channels/9876 without a problem.
The following questions should be clarified.
What is the significance of the word "often" (which implies that certain routes may not account for top-level resources)?
The current interpretation is that, OF ALL RATE LIMITED ROUTES, most are per-resource routes (since they include a top-level resource). However, the usage of the word "often" could imply that certain "resource routes" aren't per-resource.
Is a user safe assuming that all routes that include channels, guilds, and webhook parameters are per-resource?
This would follow what @advaith1 stated in #5144 (comment). To be specific, this interpretation would state that any route including a channel, guild, or webhook is rate limited using a per-resource algorithm.
Does top-level refer to endpoints that contain those resources first?
The examples in the current documentation hint at a "top-level resource" being either
- a guild, channel, or webhook that is the first parameter of a route (as shown in the examples). This would imply that a route is only a per resource rate limit if it includes a guild, channel, or webhook as the first parameter.
- an alias for a guild, channel, or webhook. This would imply that a route that simply INCUDES a guild, channel, or webhook (at any point in the route) is a per-resource rate limit.
Assumptions
Is there an assumption that everyone in the other thread has missed?
The original documentation for rate limits was completed by @shaydewael; who has yet to comment on the issue. There is a possibility that we are missing information or that Discord assumes an implementation detail the user requires.
The current assumptions are as follows.
API Consumers (users) are asked not to hard code rate limits and parse them from rate limit headers that are returned on each response. In each response, a X-RateLimit-Bucket header specifies which rate limit you are dealing with. It is implied that the user must track the Bucket Hash to determine which bucket a rate limit adheres to. Thus, a per-resource route could have multiples Bucket Hashes (for a single route) which the user implementation assigns (per resource).
A per-resource rate limit cannot be determined unless a route is 429 rate limited (with X-RateLimit-Scope: shared
). In other words, a successful request shows no difference between a per-route rate limit and a per-resource rate limit. This means that the first request (by a user) on any given route could be either a per-route or per-resource rate limit.
Obviously, users will hit rate limits if they assume a per-resource rate limit is a route rate limit or vice versa. Following the above scenario, when another request is sent, its response can include a new "Bucket" Hash indicating that a per-route rate limit has been updated; or that one is dealing with a per-resource route. There are implications from this behavior that this issue will not cover.
Most important is that rate limits must account for the time that Discord receives requests. This means a user must implement an internal rate limiter that predicts when to stop sending requests. In contrast, a user can only set the state of that internal rate limit (bucket) from a request response header. In other words, 429s are unavoidable since a request must be made first to handle rate limits. This is why shared resource rate limits don't count against users.
There are solutions to problematic behaviors above that we won't get into. For now, let's focus on getting these things clarified such that API consumers (users) can implement rate limits correctly.