@@ -535,6 +535,7 @@ describe("FairDequeuingStrategy", () => {
535
535
biases : {
536
536
concurrencyLimitBias : 0.8 ,
537
537
availableCapacityBias : 0.5 ,
538
+ queueAgeRandomization : 0.0 ,
538
539
} ,
539
540
} )
540
541
) ;
@@ -593,4 +594,99 @@ describe("FairDequeuingStrategy", () => {
593
594
expect ( highLimitPercentage ) . toBeGreaterThan ( lowLimitPercentage ) ;
594
595
}
595
596
) ;
597
+
598
+ redisTest ( "should respect ageInfluence parameter for queue ordering" , async ( { redis } ) => {
599
+ const keyProducer = createKeyProducer ( "test" ) ;
600
+ const now = Date . now ( ) ;
601
+
602
+ // Setup queues with different ages in the same environment
603
+ const queueAges = [
604
+ { id : "queue-1" , age : 5000 } , // oldest
605
+ { id : "queue-2" , age : 3000 } ,
606
+ { id : "queue-3" , age : 1000 } , // newest
607
+ ] ;
608
+
609
+ // Helper function to run iterations with a specific age influence
610
+ async function runWithQueueAgeRandomization ( queueAgeRandomization : number ) {
611
+ const strategy = new FairDequeuingStrategy ( {
612
+ tracer,
613
+ redis,
614
+ keys : keyProducer ,
615
+ defaultOrgConcurrency : 10 ,
616
+ defaultEnvConcurrency : 5 ,
617
+ parentQueueLimit : 100 ,
618
+ checkForDisabledOrgs : true ,
619
+ seed : "fixed-seed" ,
620
+ biases : {
621
+ concurrencyLimitBias : 0 ,
622
+ availableCapacityBias : 0 ,
623
+ queueAgeRandomization,
624
+ } ,
625
+ } ) ;
626
+
627
+ const positionCounts : Record < string , number [ ] > = {
628
+ "queue-1" : [ 0 , 0 , 0 ] ,
629
+ "queue-2" : [ 0 , 0 , 0 ] ,
630
+ "queue-3" : [ 0 , 0 , 0 ] ,
631
+ } ;
632
+
633
+ const iterations = 1000 ;
634
+ for ( let i = 0 ; i < iterations ; i ++ ) {
635
+ const result = await strategy . distributeFairQueuesFromParentQueue (
636
+ "parent-queue" ,
637
+ "consumer-1"
638
+ ) ;
639
+
640
+ result . forEach ( ( queueId , position ) => {
641
+ const baseQueueId = queueId . split ( ":" ) . pop ( ) ! ;
642
+ positionCounts [ baseQueueId ] [ position ] ++ ;
643
+ } ) ;
644
+ }
645
+
646
+ return positionCounts ;
647
+ }
648
+
649
+ // Setup test data
650
+ for ( const { id, age } of queueAges ) {
651
+ await setupQueue ( {
652
+ redis,
653
+ keyProducer,
654
+ parentQueue : "parent-queue" ,
655
+ score : now - age ,
656
+ queueId : id ,
657
+ orgId : "org-1" ,
658
+ envId : "env-1" ,
659
+ } ) ;
660
+ }
661
+
662
+ await setupConcurrency ( {
663
+ redis,
664
+ keyProducer,
665
+ org : { id : "org-1" , currentConcurrency : 0 , limit : 10 } ,
666
+ env : { id : "env-1" , currentConcurrency : 0 , limit : 5 } ,
667
+ } ) ;
668
+
669
+ // Test with different age influence values
670
+ const strictAge = await runWithQueueAgeRandomization ( 0 ) ; // Strict age-based ordering
671
+ const mixed = await runWithQueueAgeRandomization ( 0.5 ) ; // Mix of age and random
672
+ const fullyRandom = await runWithQueueAgeRandomization ( 1 ) ; // Completely random
673
+
674
+ console . log ( "Distribution with strict age ordering (0.0):" , strictAge ) ;
675
+ console . log ( "Distribution with mixed ordering (0.5):" , mixed ) ;
676
+ console . log ( "Distribution with random ordering (1.0):" , fullyRandom ) ;
677
+
678
+ // With strict age ordering (0.0), oldest should always be first
679
+ expect ( strictAge [ "queue-1" ] [ 0 ] ) . toBe ( 1000 ) ; // Always in first position
680
+ expect ( strictAge [ "queue-3" ] [ 0 ] ) . toBe ( 0 ) ; // Never in first position
681
+
682
+ // With fully random (1.0), positions should still allow for some age bias
683
+ const randomFirstPositionSpread = Math . abs (
684
+ fullyRandom [ "queue-1" ] [ 0 ] - fullyRandom [ "queue-3" ] [ 0 ]
685
+ ) ;
686
+ expect ( randomFirstPositionSpread ) . toBeLessThan ( 200 ) ; // Allow for larger spread in distribution
687
+
688
+ // With mixed (0.5), should show preference for age but not absolute
689
+ expect ( mixed [ "queue-1" ] [ 0 ] ) . toBeGreaterThan ( mixed [ "queue-3" ] [ 0 ] ) ; // Older preferred
690
+ expect ( mixed [ "queue-3" ] [ 0 ] ) . toBeGreaterThan ( 0 ) ; // But newer still gets chances
691
+ } ) ;
596
692
} ) ;
0 commit comments