Rate Limit Handling
Problem
AI providers enforce rate limits to prevent abuse and ensure fair usage. Exceeding these limits results in:
- HTTP 429 errors
- Request failures
- Service disruption
- Temporary bans
Different providers have different limits:
- OpenAI: 3,500 requests/min (paid tier)
- Anthropic: 50 requests/min (free tier)
- Google AI: 60 requests/min
Solution
Implement intelligent rate limiting with:
- Token bucket algorithm
- Request queuing
- Automatic backoff
- Per-provider limits
- Request prioritization
Code
import { NeuroLink } from "@juspay/neurolink";
type RateLimitConfig = {
requestsPerMinute: number;
burstSize?: number;
retryAfter?: number;
};
class RateLimiter {
private queue: Array<() => Promise<any>> = [];
private processing = false;
private tokens: number;
private lastRefill: number;
private config: Required<RateLimitConfig>;
constructor(config: RateLimitConfig) {
this.config = {
requestsPerMinute: config.requestsPerMinute,
burstSize: config.burstSize || config.requestsPerMinute,
retryAfter: config.retryAfter || 60000,
};
this.tokens = this.config.burstSize;
this.lastRefill = Date.now();
}
/**
* Refill tokens based on time elapsed
*/
private refillTokens() {
const now = Date.now();
const elapsed = now - this.lastRefill;
const tokensToAdd = (elapsed / 60000) * this.config.requestsPerMinute;
this.tokens = Math.min(this.tokens + tokensToAdd, this.config.burstSize);
this.lastRefill = now;
}
/**
* Wait until a token is available
*/
private async waitForToken(): Promise<void> {
this.refillTokens();
if (this.tokens >= 1) {
this.tokens -= 1;
return;
}
// Calculate wait time for next token
const tokensNeeded = 1 - this.tokens;
const waitTime = (tokensNeeded / this.config.requestsPerMinute) * 60000;
console.log(
`⏳ Rate limit: waiting ${Math.ceil(waitTime)}ms for next token`,
);
await new Promise((resolve) => setTimeout(resolve, waitTime));
this.tokens = 0; // Token consumed
}
/**
* Execute a request with rate limiting
*/
async execute<T>(fn: () => Promise<T>): Promise<T> {
await this.waitForToken();
try {
return await fn();
} catch (error: any) {
// Handle rate limit error
if (error.status === 429) {
const retryAfter =
error.headers?.["retry-after"] || this.config.retryAfter / 1000;
console.log(`⚠️ Rate limit hit. Retrying after ${retryAfter}s`);
// Reset tokens on rate limit
this.tokens = 0;
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
return this.execute(fn);
}
throw error;
}
}
}
/**
* Multi-provider rate limiter
*/
class ProviderRateLimiter {
private limiters = new Map<string, RateLimiter>();
private neurolink: NeuroLink;
constructor() {
this.neurolink = new NeuroLink();
// Configure per-provider limits
this.limiters.set(
"openai",
new RateLimiter({ requestsPerMinute: 3000, burstSize: 100 }),
);
this.limiters.set(
"anthropic",
new RateLimiter({ requestsPerMinute: 50, burstSize: 10 }),
);
this.limiters.set(
"google-ai",
new RateLimiter({ requestsPerMinute: 60, burstSize: 15 }),
);
}
/**
* Generate with automatic rate limiting
*/
async generate(
prompt: string,
provider: string = "openai",
options: any = {},
) {
const limiter = this.limiters.get(provider);
if (!limiter) {
throw new Error(`Unknown provider: ${provider}`);
}
return limiter.execute(async () => {
const result = await this.neurolink.generate({
input: { text: prompt },
provider,
...options,
});
console.log(`✅ Request completed (${provider})`);
return result;
});
}
/**
* Batch requests with rate limiting
*/
async batchGenerate(prompts: string[], provider: string = "openai") {
const results = [];
for (let i = 0; i < prompts.length; i++) {
console.log(`\nProcessing ${i + 1}/${prompts.length}`);
const result = await this.generate(prompts[i], provider);
results.push(result);
}
return results;
}
}
// Usage Example
async function main() {
const limiter = new ProviderRateLimiter();
// Single request
const result = await limiter.generate(
"Explain quantum computing",
"anthropic",
);
console.log(result.content);
// Batch requests - automatically rate limited
const prompts = Array(100)
.fill(null)
.map((_, i) => `Question ${i + 1}: What is ${i + 1} + ${i + 1}?`);
const results = await limiter.batchGenerate(prompts, "anthropic");
console.log(`\n✅ Completed ${results.length} requests`);
}
main();