@@ -535,6 +535,7 @@ describe("FairDequeuingStrategy", () => {
535535 biases : {
536536 concurrencyLimitBias : 0.8 ,
537537 availableCapacityBias : 0.5 ,
538+ queueAgeRandomization : 0.0 ,
538539 } ,
539540 } )
540541 ) ;
@@ -593,4 +594,99 @@ describe("FairDequeuingStrategy", () => {
593594 expect ( highLimitPercentage ) . toBeGreaterThan ( lowLimitPercentage ) ;
594595 }
595596 ) ;
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+ } ) ;
596692} ) ;
0 commit comments