mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-18 12:33:30 +01:00
feat: expose Retry-After and sublimit timeouts in RatelimitData (#9864)
* feat: expose Retry-After and sublimit timeouts in RatelimitData * chore: better docs? * Apply suggestions from code review Co-authored-by: ckohen <chaikohen@gmail.com> --------- Co-authored-by: ckohen <chaikohen@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -17,7 +17,22 @@ export class RateLimitError extends Error implements RateLimitData {
|
|||||||
|
|
||||||
public global: boolean;
|
public global: boolean;
|
||||||
|
|
||||||
public constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }: RateLimitData) {
|
public retryAfter: number;
|
||||||
|
|
||||||
|
public sublimitTimeout: number;
|
||||||
|
|
||||||
|
public constructor({
|
||||||
|
timeToReset,
|
||||||
|
limit,
|
||||||
|
method,
|
||||||
|
hash,
|
||||||
|
url,
|
||||||
|
route,
|
||||||
|
majorParameter,
|
||||||
|
global,
|
||||||
|
retryAfter,
|
||||||
|
sublimitTimeout,
|
||||||
|
}: RateLimitData) {
|
||||||
super();
|
super();
|
||||||
this.timeToReset = timeToReset;
|
this.timeToReset = timeToReset;
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
@@ -27,6 +42,8 @@ export class RateLimitError extends Error implements RateLimitData {
|
|||||||
this.route = route;
|
this.route = route;
|
||||||
this.majorParameter = majorParameter;
|
this.majorParameter = majorParameter;
|
||||||
this.global = global;
|
this.global = global;
|
||||||
|
this.retryAfter = retryAfter;
|
||||||
|
this.sublimitTimeout = sublimitTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -102,16 +102,20 @@ export class BurstHandler implements IHandler {
|
|||||||
} else if (status === 429) {
|
} else if (status === 429) {
|
||||||
// Unexpected ratelimit
|
// Unexpected ratelimit
|
||||||
const isGlobal = res.headers.has('X-RateLimit-Global');
|
const isGlobal = res.headers.has('X-RateLimit-Global');
|
||||||
|
|
||||||
await onRateLimit(this.manager, {
|
await onRateLimit(this.manager, {
|
||||||
timeToReset: retryAfter,
|
global: isGlobal,
|
||||||
limit: Number.POSITIVE_INFINITY,
|
|
||||||
method,
|
method,
|
||||||
hash: this.hash,
|
|
||||||
url,
|
url,
|
||||||
route: routeId.bucketRoute,
|
route: routeId.bucketRoute,
|
||||||
majorParameter: this.majorParameter,
|
majorParameter: this.majorParameter,
|
||||||
global: isGlobal,
|
hash: this.hash,
|
||||||
|
limit: Number.POSITIVE_INFINITY,
|
||||||
|
timeToReset: retryAfter,
|
||||||
|
retryAfter,
|
||||||
|
sublimitTimeout: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.debug(
|
this.debug(
|
||||||
[
|
[
|
||||||
'Encountered unexpected 429 rate limit',
|
'Encountered unexpected 429 rate limit',
|
||||||
|
|||||||
@@ -227,19 +227,23 @@ export class SequentialHandler implements IHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rateLimitData: RateLimitData = {
|
const rateLimitData: RateLimitData = {
|
||||||
timeToReset: timeout,
|
global: isGlobal,
|
||||||
limit,
|
|
||||||
method: options.method ?? 'get',
|
method: options.method ?? 'get',
|
||||||
hash: this.hash,
|
|
||||||
url,
|
url,
|
||||||
route: routeId.bucketRoute,
|
route: routeId.bucketRoute,
|
||||||
majorParameter: this.majorParameter,
|
majorParameter: this.majorParameter,
|
||||||
global: isGlobal,
|
hash: this.hash,
|
||||||
|
limit,
|
||||||
|
timeToReset: timeout,
|
||||||
|
retryAfter: timeout,
|
||||||
|
sublimitTimeout: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Let library users know they have hit a rate limit
|
// Let library users know they have hit a rate limit
|
||||||
this.manager.emit(RESTEvents.RateLimited, rateLimitData);
|
this.manager.emit(RESTEvents.RateLimited, rateLimitData);
|
||||||
// Determine whether a RateLimitError should be thrown
|
// Determine whether a RateLimitError should be thrown
|
||||||
await onRateLimit(this.manager, rateLimitData);
|
await onRateLimit(this.manager, rateLimitData);
|
||||||
|
|
||||||
// When not erroring, emit debug for what is happening
|
// When not erroring, emit debug for what is happening
|
||||||
if (isGlobal) {
|
if (isGlobal) {
|
||||||
this.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`);
|
this.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`);
|
||||||
@@ -345,15 +349,18 @@ export class SequentialHandler implements IHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await onRateLimit(this.manager, {
|
await onRateLimit(this.manager, {
|
||||||
timeToReset: timeout,
|
global: isGlobal,
|
||||||
limit,
|
|
||||||
method,
|
method,
|
||||||
hash: this.hash,
|
|
||||||
url,
|
url,
|
||||||
route: routeId.bucketRoute,
|
route: routeId.bucketRoute,
|
||||||
majorParameter: this.majorParameter,
|
majorParameter: this.majorParameter,
|
||||||
global: isGlobal,
|
hash: this.hash,
|
||||||
|
limit,
|
||||||
|
timeToReset: timeout,
|
||||||
|
retryAfter,
|
||||||
|
sublimitTimeout: sublimitTimeout ?? 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.debug(
|
this.debug(
|
||||||
[
|
[
|
||||||
'Encountered unexpected 429 rate limit',
|
'Encountered unexpected 429 rate limit',
|
||||||
@@ -368,6 +375,7 @@ export class SequentialHandler implements IHandler {
|
|||||||
` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,
|
` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// If caused by a sublimit, wait it out here so other requests on the route can be handled
|
// If caused by a sublimit, wait it out here so other requests on the route can be handled
|
||||||
if (sublimitTimeout) {
|
if (sublimitTimeout) {
|
||||||
// Normally the sublimit queue will not exist, however, if a sublimit is hit while in the sublimit queue, it will
|
// Normally the sublimit queue will not exist, however, if a sublimit is hit while in the sublimit queue, it will
|
||||||
|
|||||||
@@ -155,12 +155,23 @@ export interface RateLimitData {
|
|||||||
* The HTTP method being performed
|
* The HTTP method being performed
|
||||||
*/
|
*/
|
||||||
method: string;
|
method: string;
|
||||||
|
/**
|
||||||
|
* The time, in milliseconds, that will need to pass before this specific request can be retried
|
||||||
|
*/
|
||||||
|
retryAfter: number;
|
||||||
/**
|
/**
|
||||||
* The route being hit in this request
|
* The route being hit in this request
|
||||||
*/
|
*/
|
||||||
route: string;
|
route: string;
|
||||||
/**
|
/**
|
||||||
* The time, in milliseconds, until the request-lock is reset
|
* The time, in milliseconds, that will need to pass before the sublimit lock for the route resets, and requests that fall under a sublimit
|
||||||
|
* can be retried
|
||||||
|
*
|
||||||
|
* This is only present on certain sublimits, and `0` otherwise
|
||||||
|
*/
|
||||||
|
sublimitTimeout: number;
|
||||||
|
/**
|
||||||
|
* The time, in milliseconds, until the route's request-lock is reset
|
||||||
*/
|
*/
|
||||||
timeToReset: number;
|
timeToReset: number;
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user