Skip to content

Commit

Permalink
fix: prevent race condition when updating rate limit data
Browse files Browse the repository at this point in the history
Previously if you made two requests simultaneously there was a chance
that the rate limit data would get messed up. Specifically, consider the
following scenario:

1. A new rate limit window starts, with 100 requests remaining.
1. Two requests are made (A and B)
2. Request A is completed first, so now there are 99 requests left, but
   is delayed in the network
3. Request B completes second, reducing the remaining count to 98, but
   takes a faster path back
4. Response B is processed first, and the rate limit data is set to 98
   remaining.
5. Response A is processed, and the rate limit is updated to 99 left.

Clearly this is incorrect. This is a very minor inconsistency, as the
next request will overwrite the value, but it still has the potential to
confuse any algorithms that expect the value to monotonically decrease
during a period.
  • Loading branch information
thislooksfun committed Apr 10, 2022
1 parent c80b181 commit 0d1b3b7
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/gateway/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,24 @@ export abstract class Gateway {
const { headers } = response;
const remain = Number.parseInt(headers["x-ratelimit-remaining"] as string);
const reset = Number.parseInt(headers["x-ratelimit-reset"] as string);
this.rateLimit = { remaining: remain, reset: Date.now() + reset * 1000 };
debug.general(
"Updated ratelimit: %d requests remaining, resets at %s",
this.rateLimit.remaining,
new Date(this.rateLimit.reset)
);

// To prevent race conditions, only update the rate limit if either...
if (
// ...we don't have one stored
!this.rateLimit ||
// ...the stored data is expired
this.rateLimit.reset < Date.now() ||
// ...the number of remaining requests has decreased
this.rateLimit.remaining > remain
) {
this.rateLimit = { remaining: remain, reset: Date.now() + reset * 1000 };
debug.general(
"Updated ratelimit: %d requests remaining, resets at %s",
this.rateLimit.remaining,
new Date(this.rateLimit.reset)
);
}

return response;
}
}

0 comments on commit 0d1b3b7

Please sign in to comment.