@@ -295,12 +295,11 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
295295 const enableOrgLevel = yn ( process . env . ENABLE_ORGANIZATION_RUNNERS , { default : true } ) ;
296296 const maximumRunners = parseInt ( process . env . RUNNERS_MAXIMUM_COUNT || '3' ) ;
297297 const runnerLabels = process . env . RUNNER_LABELS || '' ;
298-
299298 const runnerGroup = process . env . RUNNER_GROUP_NAME || 'Default' ;
300299 const environment = process . env . ENVIRONMENT ;
301300 const ssmTokenPath = process . env . SSM_TOKEN_PATH ;
302301 const subnets = process . env . SUBNET_IDS . split ( ',' ) ;
303- const instanceTypes = process . env . INSTANCE_TYPES . split ( ',' ) ;
302+ let instanceTypes = process . env . INSTANCE_TYPES . split ( ',' ) ;
304303 const instanceTargetCapacityType = process . env . INSTANCE_TARGET_CAPACITY_TYPE ;
305304 const ephemeralEnabled = yn ( process . env . ENABLE_EPHEMERAL_RUNNERS , { default : false } ) ;
306305 const dynamicEc2ConfigEnabled = yn ( process . env . ENABLE_DYNAMIC_EC2_CONFIG , { default : false } ) ;
@@ -343,7 +342,7 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
343342 const validMessages = new Map < string , MessagesWithClient > ( ) ;
344343 const rejectedMessageIds = new Set < string > ( ) ;
345344 for ( const payload of payloads ) {
346- const { eventType, messageId, repositoryName, repositoryOwner } = payload ;
345+ const { eventType, messageId, repositoryName, repositoryOwner, labels } = payload ;
347346 if ( ephemeralEnabled && eventType !== 'workflow_job' ) {
348347 logger . warn (
349348 'Event is not supported in combination with ephemeral runners. Please ensure you have enabled workflow_job events.' ,
@@ -367,7 +366,19 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
367366 continue ;
368367 }
369368
370- const key = enableOrgLevel ? payload . repositoryOwner : `${ payload . repositoryOwner } /${ payload . repositoryName } ` ;
369+ let key = enableOrgLevel ? payload . repositoryOwner : `${ payload . repositoryOwner } /${ payload . repositoryName } ` ;
370+
371+ if ( dynamicEc2ConfigEnabled && labels ?. length ) {
372+ const requestedDynamicEc2Config = labels
373+ . find ( l => l . startsWith ( 'ghr-ec2-' ) )
374+ ?. slice ( 'ghr-ec2-' . length ) ;
375+
376+ if ( requestedDynamicEc2Config ) {
377+ const ec2Hash = ec2LabelsHash ( labels ) ;
378+ key = `${ key } /${ ec2Hash } ` ;
379+ }
380+ }
381+
371382
372383 let entry = validMessages . get ( key ) ;
373384
@@ -407,13 +418,20 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
407418 let scaleUp = 0 ;
408419 const queuedMessages : ActionRequestMessageSQS [ ] = [ ] ;
409420
421+ if ( messages . length > 0 && dynamicEc2ConfigEnabled ) {
422+ const requestedInstanceType = messages [ 0 ] . labels ?. find ( label => label . startsWith ( 'ghr-ec2-instance-type' ) ) ?. replace ( 'ghr-ec2-instance-type' , '' ) ;
423+ instanceTypes = requestedInstanceType ? [ requestedInstanceType ] : instanceTypes ;
424+ }
425+
426+
410427 for ( const message of messages ) {
411428 const messageLogger = logger . createChild ( {
412429 persistentKeys : {
413430 eventType : message . eventType ,
414431 group,
415432 messageId : message . messageId ,
416433 repository : `${ message . repositoryOwner } /${ message . repositoryName } ` ,
434+ labels : message . labels ,
417435 } ,
418436 } ) ;
419437
@@ -704,3 +722,20 @@ async function createJitConfig(
704722
705723 return failedInstances ;
706724}
725+
726+ function ec2LabelsHash ( labels : string [ ] ) : string {
727+ const prefix = 'ghr-ec2-' ;
728+
729+ const input = labels
730+ . filter ( l => l . startsWith ( prefix ) )
731+ . sort ( ) // ensure deterministic hash
732+ . join ( '|' ) ;
733+
734+ let hash = 0 ;
735+ for ( let i = 0 ; i < input . length ; i ++ ) {
736+ hash = ( hash << 5 ) - hash + input . charCodeAt ( i ) ;
737+ hash |= 0 ; // force 32-bit integer
738+ }
739+
740+ return Math . abs ( hash ) . toString ( 36 ) ;
741+ }
0 commit comments