fix(discord): prune remapped rest buckets

This commit is contained in:
Peter Steinberger
2026-04-29 13:50:17 +01:00
parent cea2da7049
commit 32db9ff538
2 changed files with 22 additions and 1 deletions

View File

@@ -144,6 +144,11 @@ export class RestScheduler<TData> {
return false;
}
private shouldPruneIdleBucket(key: string): boolean {
const mappedBucketKey = this.routeBuckets.get(key);
return mappedBucketKey !== key && !this.hasBucketReference(key);
}
private bindRouteToBucket(routeKey: string, bucketKey: string): BucketState<TData> {
const target = this.getBucket(bucketKey);
target.routeKeys.add(routeKey);
@@ -262,7 +267,7 @@ export class RestScheduler<TData> {
break;
}
if (bucket.pending.length === 0) {
if (bucket.active === 0 && !this.routeBuckets.has(key) && !this.hasBucketReference(key)) {
if (bucket.active === 0 && this.shouldPruneIdleBucket(key)) {
this.buckets.delete(key);
}
continue;

View File

@@ -83,6 +83,22 @@ describe("RequestClient", () => {
]);
});
it("prunes idle route buckets after Discord bucket remapping", async () => {
const client = new RequestClient("test-token", {
fetch: async () =>
new Response(JSON.stringify({ id: "first" }), {
status: 200,
headers: { "X-RateLimit-Bucket": "channel-messages" },
}),
});
await expect(client.get("/channels/c1/messages")).resolves.toEqual({ id: "first" });
const metrics = client.getSchedulerMetrics();
expect(metrics.activeBuckets).toBe(1);
expect(metrics.buckets.map((bucket) => bucket.key)).toEqual(["channel-messages:channels/c1"]);
});
it("waits for a learned bucket reset before dispatching the next request", async () => {
vi.useFakeTimers();
vi.setSystemTime(0);