Skip to content

Instantly share code, notes, and snippets.

@Goblinlordx
Created July 31, 2024 06:50
Show Gist options
  • Save Goblinlordx/cfbdbec2c442a79f4017a9f8cdb3a234 to your computer and use it in GitHub Desktop.
Save Goblinlordx/cfbdbec2c442a79f4017a9f8cdb3a234 to your computer and use it in GitHub Desktop.
Token Bucket Rate Limiter
export class RateLimiter {
private maxCalls: number
private interval: number
private tokens: number
private lastRefill: number
private callQueue: Array<() => void>
constructor(callsPerSecond: number, initialTokens: number = 0) {
this.maxCalls = callsPerSecond
this.interval = 1000 / this.maxCalls
this.tokens = initialTokens
this.lastRefill = Date.now()
this.callQueue = []
}
private refillTokens() {
const now = Date.now()
const elapsed = now - this.lastRefill
if (elapsed <= 0) return
const newTokens = Math.floor((elapsed / 1000) * this.maxCalls)
if (newTokens <= 0) return
this.tokens = Math.min(this.tokens + newTokens, this.maxCalls)
this.lastRefill = now
}
private processQueue() {
this.refillTokens()
while (this.tokens > 0 && this.callQueue.length > 0) {
const fn = this.callQueue.shift()
if (!fn) return
this.tokens--
fn()
}
if (this.callQueue.length > 0) {
setTimeout(() => this.processQueue(), this.interval)
}
}
public schedule<T extends (...args: unknown[]) => ReturnType<T>>(
fn: T,
...args: Parameters<T>
): Promise<ReturnType<T>> {
return new Promise<ReturnType<T>>((resolve, reject) => {
this.callQueue.push(() => {
try {
const result = fn(...args)
resolve(result)
} catch (error) {
reject(error)
}
})
this.processQueue()
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment