|
|
import { DuckAI } from "./duckai"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class SharedRateLimitTester { |
|
|
private duckAI: DuckAI; |
|
|
|
|
|
constructor() { |
|
|
this.duckAI = new DuckAI(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getCurrentStatus() { |
|
|
const status = this.duckAI.getRateLimitStatus(); |
|
|
return { |
|
|
...status, |
|
|
utilizationPercentage: |
|
|
(status.requestsInCurrentWindow / status.maxRequestsPerMinute) * 100, |
|
|
timeUntilWindowResetMinutes: Math.ceil( |
|
|
status.timeUntilWindowReset / 60000 |
|
|
), |
|
|
recommendedWaitTimeSeconds: Math.ceil(status.recommendedWaitTime / 1000), |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printStatus() { |
|
|
const status = this.getCurrentStatus(); |
|
|
|
|
|
console.log("\nπ DuckAI Rate Limit Status (Shared Tester):"); |
|
|
console.log("ββββββββββββββββββββββββββββββββββββββββ"); |
|
|
console.log( |
|
|
`π Requests in current window: ${status.requestsInCurrentWindow}/${status.maxRequestsPerMinute}` |
|
|
); |
|
|
console.log(`π Utilization: ${status.utilizationPercentage.toFixed(1)}%`); |
|
|
console.log( |
|
|
`β° Window resets in: ${status.timeUntilWindowResetMinutes} minutes` |
|
|
); |
|
|
console.log( |
|
|
`π¦ Currently limited: ${status.isCurrentlyLimited ? "β Yes" : "β
No"}` |
|
|
); |
|
|
|
|
|
if (status.recommendedWaitTimeSeconds > 0) { |
|
|
console.log( |
|
|
`β³ Recommended wait: ${status.recommendedWaitTimeSeconds} seconds` |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
const barLength = 20; |
|
|
const filledLength = Math.round( |
|
|
(status.utilizationPercentage / 100) * barLength |
|
|
); |
|
|
const bar = "β".repeat(filledLength) + "β".repeat(barLength - filledLength); |
|
|
console.log( |
|
|
`π Usage: [${bar}] ${status.utilizationPercentage.toFixed(1)}%` |
|
|
); |
|
|
console.log("ββββββββββββββββββββββββββββββββββββββββ\n"); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async testRateLimits( |
|
|
numberOfRequests: number = 5, |
|
|
delayBetweenRequests: number = 1000 |
|
|
) { |
|
|
console.log( |
|
|
`π§ͺ Testing rate limits with ${numberOfRequests} requests (${delayBetweenRequests}ms delay)...` |
|
|
); |
|
|
console.log( |
|
|
"π‘ Using DuckAI class - data will be shared across processes!" |
|
|
); |
|
|
|
|
|
for (let i = 1; i <= numberOfRequests; i++) { |
|
|
console.log(`\nπ€ Making request ${i}/${numberOfRequests}...`); |
|
|
|
|
|
try { |
|
|
const startTime = Date.now(); |
|
|
|
|
|
const response = await this.duckAI.chat({ |
|
|
model: "gpt-4o-mini", |
|
|
messages: [{ role: "user", content: `Shared test request ${i}` }], |
|
|
}); |
|
|
|
|
|
const endTime = Date.now(); |
|
|
const responseTime = endTime - startTime; |
|
|
|
|
|
console.log(`β
Request ${i} successful (${responseTime}ms)`); |
|
|
this.printStatus(); |
|
|
|
|
|
if (i < numberOfRequests) { |
|
|
console.log( |
|
|
`β³ Waiting ${delayBetweenRequests}ms before next request...` |
|
|
); |
|
|
await new Promise((resolve) => |
|
|
setTimeout(resolve, delayBetweenRequests) |
|
|
); |
|
|
} |
|
|
} catch (error) { |
|
|
const errorMessage = |
|
|
error instanceof Error ? error.message : String(error); |
|
|
console.log(`β Request ${i} failed:`, errorMessage); |
|
|
this.printStatus(); |
|
|
|
|
|
|
|
|
if (errorMessage.includes("Rate limited")) { |
|
|
const waitTime = |
|
|
this.getCurrentStatus().recommendedWaitTimeSeconds * 1000; |
|
|
console.log(`β³ Rate limited! Waiting ${waitTime}ms...`); |
|
|
await new Promise((resolve) => setTimeout(resolve, waitTime)); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
console.log("\nπ Shared rate limit test completed!"); |
|
|
console.log( |
|
|
"π‘ Data has been written to shared store for cross-process monitoring!" |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getRecommendations() { |
|
|
const status = this.getCurrentStatus(); |
|
|
const recommendations: string[] = []; |
|
|
|
|
|
if (status.utilizationPercentage > 80) { |
|
|
recommendations.push( |
|
|
"β οΈ High utilization detected. Consider implementing request queuing." |
|
|
); |
|
|
} |
|
|
|
|
|
if (status.recommendedWaitTimeSeconds > 0) { |
|
|
recommendations.push( |
|
|
`β³ Wait ${status.recommendedWaitTimeSeconds}s before next request.` |
|
|
); |
|
|
} |
|
|
|
|
|
if (status.isCurrentlyLimited) { |
|
|
recommendations.push( |
|
|
"π« Currently rate limited. Wait for window reset or implement exponential backoff." |
|
|
); |
|
|
} |
|
|
|
|
|
if (status.utilizationPercentage < 50) { |
|
|
recommendations.push( |
|
|
"β
Good utilization level. You can safely increase request frequency." |
|
|
); |
|
|
} |
|
|
|
|
|
recommendations.push( |
|
|
"π‘ Consider implementing request batching for better efficiency." |
|
|
); |
|
|
recommendations.push("π Use exponential backoff for retry logic."); |
|
|
recommendations.push("π Monitor rate limits continuously in production."); |
|
|
recommendations.push( |
|
|
"π‘ Use shared monitoring for cross-process visibility." |
|
|
); |
|
|
|
|
|
return recommendations; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printRecommendations() { |
|
|
const recommendations = this.getRecommendations(); |
|
|
|
|
|
console.log("\nπ‘ Rate Limit Recommendations:"); |
|
|
console.log("ββββββββββββββββββββββββββββββββββββββββ"); |
|
|
recommendations.forEach((rec) => console.log(rec)); |
|
|
console.log("ββββββββββββββββββββββββββββββββββββββββ\n"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (require.main === module) { |
|
|
const tester = new SharedRateLimitTester(); |
|
|
|
|
|
|
|
|
const args = process.argv.slice(2); |
|
|
const command = args[0]; |
|
|
|
|
|
switch (command) { |
|
|
case "status": |
|
|
tester.printStatus(); |
|
|
tester.printRecommendations(); |
|
|
break; |
|
|
|
|
|
case "test": |
|
|
const requests = parseInt(args[1]) || 5; |
|
|
const delay = parseInt(args[2]) || 1000; |
|
|
tester.testRateLimits(requests, delay).then(() => { |
|
|
tester.printRecommendations(); |
|
|
process.exit(0); |
|
|
}); |
|
|
break; |
|
|
|
|
|
default: |
|
|
console.log("π DuckAI Shared Rate Limit Tester"); |
|
|
console.log("π‘ Uses DuckAI class - data is shared across processes!"); |
|
|
console.log(""); |
|
|
console.log("Usage:"); |
|
|
console.log( |
|
|
" bun run src/shared-rate-limit-tester.ts status # Show current status" |
|
|
); |
|
|
console.log( |
|
|
" bun run src/shared-rate-limit-tester.ts test [requests] [delay] # Test rate limits (shared)" |
|
|
); |
|
|
console.log(""); |
|
|
console.log("Examples:"); |
|
|
console.log(" bun run src/shared-rate-limit-tester.ts status"); |
|
|
console.log(" bun run src/shared-rate-limit-tester.ts test 10 2000"); |
|
|
console.log(""); |
|
|
console.log("π‘ For cross-process monitoring, run this in one terminal:"); |
|
|
console.log(" bun run src/shared-rate-limit-tester.ts test 20 3000"); |
|
|
console.log(""); |
|
|
console.log("And this in another terminal:"); |
|
|
console.log(" bun run src/shared-rate-limit-monitor.ts monitor 2"); |
|
|
break; |
|
|
} |
|
|
} |
|
|
|