Token Bucket Rate Limiter Async
Implement an async token bucket limiter with burst capacity, refill rate, per-key isolation, and wait semantics for queue-friendly callers.
Code
// async token bucket rate limiter with jitter
class TokenBucket {
private tokens: number;
private lastRefill: number;
constructor(
private readonly capacity: number,
private readonly refillPerSecond: number,
) {
this.tokens = capacity;
this.lastRefill = performance.now();
}
private refill(now: number) {
const elapsed = (now - this.lastRefill) / 1000;
this.tokens = Math.min(
this.capacity,
this.tokens + elapsed * this.refillPerSecond,
);
this.lastRefill = now;
}
tryTake(count = 1): boolean {
this.refill(performance.now());
if (this.tokens < count) return false;
this.tokens -= count;
return true;
}
async take(count = 1): Promise<void> {
while (!this.tryTake(count)) {
const deficit = count - this.tokens;
const waitMs = (deficit / this.refillPerSecond) * 1000;
await new Promise((r) => setTimeout(r, Math.max(waitMs, 10)));
}
}
}
const buckets = new Map<string, TokenBucket>();
function bucketFor(key: string) {
let b = buckets.get(key);
if (!b) {
b = new TokenBucket(10, 5);
buckets.set(key, b);
}
return b;
}
await bucketFor('api:upload').take(3);
console.log('upload quota acquired, burst-friendly');
const immediate = bucketFor('api:upload').tryTake(8);
console.log('immediate take of 8:', immediate);Report a problem with this exampleOpens a pre-filled issue on GitHub.