@@ -513,6 +513,36 @@ describe("AIMDBucket", () => {
513513 bucket = new AIMDBucket ( { initialRate : 10 } ) ;
514514 } ) ;
515515
516+ it ( "should process pending requests when tokens timeout automatically" , async ( ) => {
517+ // This test reproduces the lockup bug
518+ bucket = new AIMDBucket ( {
519+ initialRate : 1 , // Very low rate
520+ tokenReturnTimeoutMs : 1000 , // Short timeout for testing
521+ } ) ;
522+
523+ // Acquire many tokens at once - first one should be immediate, rest should be pending
524+ const tokenPromises = Array . from ( { length : 5 } , ( ) => bucket . acquire ( ) ) ;
525+
526+ // Wait for first token to be resolved
527+ await vi . advanceTimersByTimeAsync ( 50 ) ;
528+
529+ const stats1 = bucket . getStatistics ( ) ;
530+ expect ( stats1 . tokensIssued ) . toBe ( 1 ) ; // Only 1 token issued immediately
531+ expect ( stats1 . pendingCount ) . toBe ( 4 ) ; // 4 requests should be pending
532+
533+ // Don't complete the first token - let it timeout automatically. Advance time past the token timeout
534+ await vi . advanceTimersByTimeAsync ( 1100 ) ;
535+
536+ // After timeout, pending requests should start being processed due to refill
537+ await vi . advanceTimersByTimeAsync ( 3000 ) ; // Allow time for refill (3 more tokens at 1/sec)
538+
539+ const stats2 = bucket . getStatistics ( ) ;
540+ expect ( stats2 . tokensIssued ) . toBeGreaterThan ( 1 ) ;
541+ expect ( stats2 . pendingCount ) . toBeLessThan ( 4 ) ;
542+
543+ await bucket . shutdown ( ) ;
544+ } ) ;
545+
516546 it ( "should handle rapid acquisition bursts" , async ( ) => {
517547 // Test that we can acquire tokens up to the bucket capacity
518548 const initialTokens = await Promise . all ( Array . from ( { length : 10 } , ( ) => bucket . acquire ( ) ) ) ;
0 commit comments