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', () => { await t.step('throws when hit if second limit exceeded', () => {
assertEquals(limiter.client('test').limiter, limiter1);
assertThrows(() => limiter.client('test').hit(), Error); 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 { export class MultiRateLimiter {
constructor(private limiters: RateLimiter[]) {} constructor(private limiters: RateLimiter[]) {}
client(key: string): RateLimiterClient { client(key: string): MultiRateLimiterClient {
return new MultiRateLimiterClient(key, this.limiters); 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 { get hits(): number {
return this.limiters[0].client(this.key).hits; return this.limiter.client(this.key).hits;
} }
get resetAt(): Date { get resetAt(): Date {
return this.limiters[0].client(this.key).resetAt; return this.limiter.client(this.key).resetAt;
} }
get remaining(): number { get remaining(): number {
return this.limiters[0].client(this.key).remaining; return this.limiter.client(this.key).remaining;
} }
hit(n?: number): void { hit(n?: number): void {