Skip to content

Commit 2da7824

Browse files
feat: allow to use dynamic instance type in multiple events
1 parent 7319666 commit 2da7824

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
@@ -272,12 +272,11 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
272272
const enableOrgLevel = yn(process.env.ENABLE_ORGANIZATION_RUNNERS, { default: true });
273273
const maximumRunners = parseInt(process.env.RUNNERS_MAXIMUM_COUNT || '3');
274274
const runnerLabels = process.env.RUNNER_LABELS || '';
275-
276275
const runnerGroup = process.env.RUNNER_GROUP_NAME || 'Default';
277276
const environment = process.env.ENVIRONMENT;
278277
const ssmTokenPath = process.env.SSM_TOKEN_PATH;
279278
const subnets = process.env.SUBNET_IDS.split(',');
280-
const instanceTypes = process.env.INSTANCE_TYPES.split(',');
279+
let instanceTypes = process.env.INSTANCE_TYPES.split(',');
281280
const instanceTargetCapacityType = process.env.INSTANCE_TARGET_CAPACITY_TYPE;
282281
const ephemeralEnabled = yn(process.env.ENABLE_EPHEMERAL_RUNNERS, { default: false });
283282
const dynamicEc2ConfigEnabled = yn(process.env.ENABLE_DYNAMIC_EC2_CONFIG, { default: false });
@@ -320,7 +319,7 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
320319
const validMessages = new Map<string, MessagesWithClient>();
321320
const invalidMessages: string[] = [];
322321
for (const payload of payloads) {
323-
const { eventType, messageId, repositoryName, repositoryOwner } = payload;
322+
const { eventType, messageId, repositoryName, repositoryOwner, labels } = payload;
324323
if (ephemeralEnabled && eventType !== 'workflow_job') {
325324
logger.warn(
326325
'Event is not supported in combination with ephemeral runners. Please ensure you have enabled workflow_job events.',
@@ -344,7 +343,19 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
344343
continue;
345344
}
346345

347-
const key = enableOrgLevel ? payload.repositoryOwner : `${payload.repositoryOwner}/${payload.repositoryName}`;
346+
let key = enableOrgLevel ? payload.repositoryOwner : `${payload.repositoryOwner}/${payload.repositoryName}`;
347+
348+
if (dynamicEc2ConfigEnabled && labels?.length) {
349+
const requestedDynamicEc2Config = labels
350+
.find(l => l.startsWith('ghr-ec2-'))
351+
?.slice('ghr-ec2-'.length);
352+
353+
if (requestedDynamicEc2Config) {
354+
const ec2Hash = ec2LabelsHash(labels);
355+
key = `${key}/${ec2Hash}`;
356+
}
357+
}
358+
348359

349360
let entry = validMessages.get(key);
350361

@@ -383,13 +394,20 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
383394
// Work out how much we want to scale up by.
384395
let scaleUp = 0;
385396

397+
if (messages.length > 0 && dynamicEc2ConfigEnabled) {
398+
const requestedInstanceType = messages[0].labels?.find(label => label.startsWith('ghr-ec2-instance-type'))?.replace('ghr-ec2-instance-type', '');
399+
instanceTypes = requestedInstanceType ? [requestedInstanceType] : instanceTypes;
400+
}
401+
402+
386403
for (const message of messages) {
387404
const messageLogger = logger.createChild({
388405
persistentKeys: {
389406
eventType: message.eventType,
390407
group,
391408
messageId: message.messageId,
392409
repository: `${message.repositoryOwner}/${message.repositoryName}`,
410+
labels: message.labels,
393411
},
394412
});
395413

@@ -399,7 +417,7 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
399417
continue;
400418
}
401419

402-
scaleUp++;
420+
scaleUp++;
403421
}
404422

405423
if (scaleUp === 0) {
@@ -622,3 +640,20 @@ async function createJitConfig(githubRunnerConfig: CreateGitHubRunnerConfig, ins
622640
}
623641
}
624642
}
643+
644+
function ec2LabelsHash(labels: string[]): string {
645+
const prefix = 'ghr-ec2-';
646+
647+
const input = labels
648+
.filter(l => l.startsWith(prefix))
649+
.sort() // ensure deterministic hash
650+
.join('|');
651+
652+
let hash = 0;
653+
for (let i = 0; i < input.length; i++) {
654+
hash = (hash << 5) - hash + input.charCodeAt(i);
655+
hash |= 0; // force 32-bit integer
656+
}
657+
658+
return Math.abs(hash).toString(36);
659+
}

0 commit comments

Comments
 (0)