MultiRateLimiter: ensure the active limiter is used for ratelimit values

This commit is contained in:
Alex Gleason 2025-01-25 15:31:49 -06:00
parent 43a47770f4
commit fd312032a4
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
2 changed files with 12 additions and 4 deletions

View file

@ -34,6 +34,8 @@ Deno.test('MultiRateLimiter', async (t) => {
});
await t.step('throws when hit if second limit exceeded', () => {
assertEquals(limiter.client('test').limiter, limiter1);
assertThrows(() => limiter.client('test').hit(), Error);
assertEquals(limiter.client('test').limiter, limiter2);
});
});

View file

@ -3,7 +3,7 @@ import { RateLimiter, RateLimiterClient } from './types.ts';
export class MultiRateLimiter {
constructor(private limiters: RateLimiter[]) {}
client(key: string): RateLimiterClient {
client(key: string): MultiRateLimiterClient {
return new MultiRateLimiterClient(key, this.limiters);
}
}
@ -15,16 +15,22 @@ class MultiRateLimiterClient implements RateLimiterClient {
}
}
/** Returns the _active_ limiter, which is either the first exceeded or the first. */
get limiter(): RateLimiter {
const exceeded = this.limiters.find((limiter) => limiter.client(this.key).remaining < 0);
return exceeded ?? this.limiters[0];
}
get hits(): number {
return this.limiters[0].client(this.key).hits;
return this.limiter.client(this.key).hits;
}
get resetAt(): Date {
return this.limiters[0].client(this.key).resetAt;
return this.limiter.client(this.key).resetAt;
}
get remaining(): number {
return this.limiters[0].client(this.key).remaining;
return this.limiter.client(this.key).remaining;
}
hit(n?: number): void {