Skip to content

Commit 67eef52

Browse files
feat: allow to use dynamic instance type in multiple events
1 parent cc915e2 commit 67eef52

1 file changed

Lines changed: 40 additions & 5 deletions

File tree

  • lambdas/functions/control-plane/src/scale-runners

lambdas/functions/control-plane/src/scale-runners/scale-up.ts

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,11 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
237237
const enableOrgLevel = yn(process.env.ENABLE_ORGANIZATION_RUNNERS, { default: true });
238238
const maximumRunners = parseInt(process.env.RUNNERS_MAXIMUM_COUNT || '3');
239239
const runnerLabels = process.env.RUNNER_LABELS || '';
240-
241240
const runnerGroup = process.env.RUNNER_GROUP_NAME || 'Default';
242241
const environment = process.env.ENVIRONMENT;
243242
const ssmTokenPath = process.env.SSM_TOKEN_PATH;
244243
const subnets = process.env.SUBNET_IDS.split(',');
245-
const instanceTypes = process.env.INSTANCE_TYPES.split(',');
244+
let instanceTypes = process.env.INSTANCE_TYPES.split(',');
246245
const instanceTargetCapacityType = process.env.INSTANCE_TARGET_CAPACITY_TYPE;
247246
const ephemeralEnabled = yn(process.env.ENABLE_EPHEMERAL_RUNNERS, { default: false });
248247
const dynamicEc2ConfigEnabled = yn(process.env.ENABLE_DYNAMIC_EC2_CONFIG, { default: false });
@@ -281,7 +280,7 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
281280
const validMessages = new Map<string, MessagesWithClient>();
282281
const invalidMessages: string[] = [];
283282
for (const payload of payloads) {
284-
const { eventType, messageId, repositoryName, repositoryOwner } = payload;
283+
const { eventType, messageId, repositoryName, repositoryOwner, labels } = payload;
285284
if (ephemeralEnabled && eventType !== 'workflow_job') {
286285
logger.warn(
287286
'Event is not supported in combination with ephemeral runners. Please ensure you have enabled workflow_job events.',
@@ -305,7 +304,19 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
305304
continue;
306305
}
307306

308-
const key = enableOrgLevel ? payload.repositoryOwner : `${payload.repositoryOwner}/${payload.repositoryName}`;
307+
let key = enableOrgLevel ? payload.repositoryOwner : `${payload.repositoryOwner}/${payload.repositoryName}`;
308+
309+
if (dynamicEc2ConfigEnabled && labels?.length) {
310+
const requestedDynamicEc2Config = labels
311+
.find(l => l.startsWith('ghr-ec2-'))
312+
?.slice('ghr-ec2-'.length);
313+
314+
if (requestedDynamicEc2Config) {
315+
const ec2Hash = ec2LabelsHash(labels);
316+
key = `${key}/${ec2Hash}`;
317+
}
318+
}
319+
309320

310321
let entry = validMessages.get(key);
311322

@@ -344,13 +355,20 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
344355
// Work out how much we want to scale up by.
345356
let scaleUp = 0;
346357

358+
if (messages.length > 0 && dynamicEc2ConfigEnabled) {
359+
const requestedInstanceType = messages[0].labels?.find(label => label.startsWith('ghr-ec2-instance-type'))?.replace('ghr-ec2-instance-type', '');
360+
instanceTypes = requestedInstanceType ? [requestedInstanceType] : instanceTypes;
361+
}
362+
363+
347364
for (const message of messages) {
348365
const messageLogger = logger.createChild({
349366
persistentKeys: {
350367
eventType: message.eventType,
351368
group,
352369
messageId: message.messageId,
353370
repository: `${message.repositoryOwner}/${message.repositoryName}`,
371+
labels: message.labels,
354372
},
355373
});
356374

@@ -360,7 +378,7 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
360378
continue;
361379
}
362380

363-
scaleUp++;
381+
scaleUp++;
364382
}
365383

366384
if (scaleUp === 0) {
@@ -582,3 +600,20 @@ async function createJitConfig(githubRunnerConfig: CreateGitHubRunnerConfig, ins
582600
}
583601
}
584602
}
603+
604+
function ec2LabelsHash(labels: string[]): string {
605+
const prefix = 'ghr-ec2-';
606+
607+
const input = labels
608+
.filter(l => l.startsWith(prefix))
609+
.sort() // ensure deterministic hash
610+
.join('|');
611+
612+
let hash = 0;
613+
for (let i = 0; i < input.length; i++) {
614+
hash = (hash << 5) - hash + input.charCodeAt(i);
615+
hash |= 0; // force 32-bit integer
616+
}
617+
618+
return Math.abs(hash).toString(36);
619+
}

0 commit comments

Comments
 (0)