-
-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(Rest): better handling of global rate limit and invalid request tracking #4711
Conversation
@NotSugden I made the changes you suggested (in a previous version of my changes I had been using the variables outside of the block scope, but since that's no longer the case, I agree that |
i don't have anymore suggestions for a review, and its not up to me what gets merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid colliding with the global global
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR does not fix the rate limit issue.
I tried it with a ~650k servers bot using 320 shards.
10k limit was reached even with this handling.
Requests were not stopped when reaching the 10k bad requests limits and were spamming the API even being banned.
There are certainly plenty of cases that this PR doesn't catch, but that's true of all discord.js rate limit handling now. For example if a bot restarts, it loses all rate limit state information, but Discord still knows how close to a rate limit you are. There is also no tracking for rate sub-limits like the 2/10 minute limit on channel renames/topic changes. This is a best effort fix that should work for most (non-sharded, see below) bots.
I could be wrong, but my understanding of sharding was that each shard is normally handled by a separate process (a child process of the original bot process if you use I'd suggest a workaround instead: simply set the
This PR doesn't attempt to do anything to prevent you from hitting the 10k bad request limit, it just provides a mechanism for you to be aware that you are approaching the limit via the |
by the way, |
That is completely wrong for the current version of the lib. |
@tipakA while it seems like you're correct according to the OLD docs, what tipped me off to this was running a test case (which you obviously need a globally-ratelimited bot to reproduce, so you'll have to trust me): const { Client } = require("discord.js");
const c = new Client();
c.token = yourTokenVariable;
c.on("debug", (msg) => {
console.log(msg);
const handler = c.rest.handlers.get("/gateway/bot");
console.log(`429 retryAfter: ${handler.retryAfter}`);
});
c.on("rateLimit", (rl) => console.log(`Ratelimit on '${rl.route}' => ${rl.timeout}`));
c.api.gateway.bot.get().then((res) => {
console.dir(res);
}).catch((err) => {
console.error(err);
}); running this I was greeted with the lovely sight:
so honestly seems like Discord messed up and changed it. |
I'll be honest, I gave up on anyone merging this like a month ago. If someone who actually is a maintainer for discord.js wants to weigh in that they would want this in a future version, please let me know - I'm happy to update the PR for Discord API v8/discord.js v13(?). I continue to think this would be a super helpful feature, but I have no intention of updating this code myself again and again just to keep having a well thought out PR ignored by those with the authority to review and merge it. No offense, obviously you all have lives and other things to do besides merge PRs all day 😃 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These small nits aside, this is looking pretty good
This needs a rebase. |
Since this is actually moving, I'm happy to make some changes to bring it up to the current state. Do you actually want it rebased onto master @iCrawl, or should I just merge master into my branch? Both probably equivalently easy for me, I'm just in favor of whatever doesn't screw up this Pull Request :) |
Either way is fine as long as the conflicts get resolved. |
Rebase complete |
@ahnolds is this pr compatible with api v8?
(also there's a conflict) |
Probably not right now - when I submitted it, discord.js was still working with v6/v7. The changes should be relatively minor (potentially just one division by 1000). I'll try to verify and update this week/weekend. |
Add customizable restGlobalRateLimit to pre-emptively monitor global rate limit Report the real tiemout when the global rate limit is hit Handle rate sublimits for individual requests Remove unnecessary double wait from some rate limit handling code paths
Emit a warning periodically as the the number of invalid (401, 403, 429) rest requests increases to allow clients to avoid the 10k invalid requests in 10 minutes temporary ban
Declare variables with let rather than var (in a previous version these variables had been used outside of block scope). Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com>
Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Avoid colliding with the global `global` Co-authored-by: Papaia <43409674+Papaia@users.noreply.github.com>
Should be good now. On an unrelated note, I'll have another (very small) PR coming in shortly - looks like 5ac3b57 broke channel renames since a rename doesn't set the type property in the inbound data and the GuildChannel.type property is a string rather than the int that Discord expects. |
#5251 is already a thing. |
Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you tested all these changes and no unexpected behavior happened, lgtm i suppose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm generally not happy with this PR's idea because the lack of unit testing (which -next REST's has, but isn't ready yet), but if it's tested and works perfectly, LGTM.
partials: [], | ||
restWsBridgeTimeout: 5000, | ||
restRequestTimeout: 15000, | ||
restGlobalRateLimit: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does this not default to 50?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two reasons:
- I thought it best to maintain the current behavior when I originally wrote this
- That would be a bad value to use for a bot with the mystery higher global rate limit in >150k servers
I certainly don't object if the d.js team thinks it would be better to set a default of 50.
Ported from discordjs/discord.js#4711 refactor(SequentialHandler): use timers/promises refactor(SequentialHandler): move global checks to each request Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com> fix: separate queue for sub limits refactor(SequentialHandler): address PR comments Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com> refactor(SequentialHandler): better sublimit handling refactor: address pr comments Co-Authored-By: Vlad Frangu <kingdgrizzle@gmail.com> Co-Authored-By: Antonio Román <kyradiscord@gmail.com> Co-Authored-By: Noel <icrawltogo@gmail.com> test: add sublimit tests refactor(Util): only check route once refactor: rename globalLimit Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com> fix: address pr comments Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com> refactor(Utils): use enum Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com> Update packages/rest/src/lib/handlers/SequentialHandler.ts
Please describe the changes this PR makes and why it should be merged:
Currently, there is no support for preemptively avoiding the global rate limit - any requests in-flight to Discord at the time the limit is reached will simply result in 429s. This PR adds a configurable preemptive global rate limit option
restGlobalRateLimit
(defaulting to zero, which maintains the current behavior). Additionally, it makes the following related enhancements:This PR also adds tracking for the number of invalid REST requests (those that result in a 401, 403, or 429 status code) to aid in avoiding the 10k invalid requests in 10 minutes temporary ban. The library user can configure a warning period to through the new option
invalidRequestWarningInterval
(defaulting to zero, which emits no warnings), which causes anINVALID_REQUEST_WARNING
event to be emitted with the number of invalid requests made in the 10 minute period and the amount of time left in the period. That is, ifinvalidRequestWarningInterval = 500
, then an event will be emitted at the 500th, 1000th, 1500th, and so on invalid request in the 10 minute period.Status
Semantic versioning classification: