@@ -44,16 +44,16 @@ interface AvailableKey {
4444/**
4545 * HostedKeyRateLimiter provides:
4646 * 1. Per-billing-actor rate limiting (enforced - blocks actors who exceed their limit)
47- * 2. Least-loaded key selection (distributes requests evenly across keys)
47+ * 2. Round-robin key selection (distributes requests evenly across keys)
4848 * 3. Post-execution dimension usage tracking for custom rate limits
4949 *
5050 * The billing actor is typically a workspace ID, meaning rate limits are shared
5151 * across all users within the same workspace.
5252 */
5353export class HostedKeyRateLimiter {
5454 private storage : RateLimitStorageAdapter
55- /** In-memory request counters per key: " provider:keyIndex" -> count */
56- private keyRequestCounts = new Map < string , number > ( )
55+ /** Round-robin counter per provider for even key distribution */
56+ private roundRobinCounters = new Map < string , number > ( )
5757
5858 constructor ( storage ?: RateLimitStorageAdapter ) {
5959 this . storage = storage ?? createStorageAdapter ( )
@@ -176,11 +176,11 @@ export class HostedKeyRateLimiter {
176176 }
177177
178178 /**
179- * Acquire the best available key.
179+ * Acquire an available key via round-robin selection .
180180 *
181181 * For both modes:
182182 * 1. Per-billing-actor request rate limiting (enforced): blocks actors who exceed their request limit
183- * 2. Least-loaded key selection: picks the key with fewest in-flight requests
183+ * 2. Round-robin key selection: cycles through available keys for even distribution
184184 *
185185 * For `custom` mode additionally:
186186 * 3. Pre-checks dimension budgets: blocks if any dimension is already depleted
@@ -229,31 +229,21 @@ export class HostedKeyRateLimiter {
229229 }
230230 }
231231
232- let leastLoaded = availableKeys [ 0 ]
233- let minCount = this . getKeyCount ( provider , leastLoaded . keyIndex )
234-
235- for ( let i = 1 ; i < availableKeys . length ; i ++ ) {
236- const count = this . getKeyCount ( provider , availableKeys [ i ] . keyIndex )
237- if ( count < minCount ) {
238- minCount = count
239- leastLoaded = availableKeys [ i ]
240- }
241- }
242-
243- this . incrementKeyCount ( provider , leastLoaded . keyIndex )
232+ const counter = this . roundRobinCounters . get ( provider ) ?? 0
233+ const selected = availableKeys [ counter % availableKeys . length ]
234+ this . roundRobinCounters . set ( provider , counter + 1 )
244235
245236 logger . debug ( `Selected hosted key for ${ provider } ` , {
246237 provider,
247- keyIndex : leastLoaded . keyIndex ,
248- envVarName : leastLoaded . envVarName ,
249- requestCount : minCount + 1 ,
238+ keyIndex : selected . keyIndex ,
239+ envVarName : selected . envVarName ,
250240 } )
251241
252242 return {
253243 success : true ,
254- key : leastLoaded . key ,
255- keyIndex : leastLoaded . keyIndex ,
256- envVarName : leastLoaded . envVarName ,
244+ key : selected . key ,
245+ keyIndex : selected . keyIndex ,
246+ envVarName : selected . envVarName ,
257247 }
258248 }
259249
@@ -337,15 +327,6 @@ export class HostedKeyRateLimiter {
337327
338328 return { dimensions : results }
339329 }
340-
341- private getKeyCount ( provider : string , keyIndex : number ) : number {
342- return this . keyRequestCounts . get ( `${ provider } :${ keyIndex } ` ) ?? 0
343- }
344-
345- private incrementKeyCount ( provider : string , keyIndex : number ) : void {
346- const key = `${ provider } :${ keyIndex } `
347- this . keyRequestCounts . set ( key , ( this . keyRequestCounts . get ( key ) ?? 0 ) + 1 )
348- }
349330}
350331
351332let cachedInstance : HostedKeyRateLimiter | null = null
0 commit comments