Skip to content

Commit 34e2f4b

Browse files
committed
feat(pool): Allow to optionally include busy runners into the pool
'pool_config' is useful when one wants to ensure that a certain number of runners is running within given time periods. However, when 'pool_config' is used in a combination with persistent runners, the pool lambda tends to spin up new runner instance when it sees that some existing runners are online, but busy. As a result, with frequent pool lambda checks, the total size of the runners pool tends to grow more than desired (without respecting 'runners_maximum_count', which is only considered by the 'scale_up' lambda). These changes introduce a new 'pool_include_busy_runners' module variable to make it possbile to include all online runners (both idle and busy) into the pool, so that the pool's lambda only tops up the pool if not enough runners are online.
1 parent 6d3b7db commit 34e2f4b

File tree

8 files changed

+42
-3
lines changed

8 files changed

+42
-3
lines changed

lambdas/functions/control-plane/src/pool/pool.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,22 @@ describe('Test simple pool.', () => {
336336
expect(createRunners).toHaveBeenCalledWith(expect.anything(), expect.anything(), 1, expect.anything());
337337
});
338338
});
339+
340+
describe('With INCLUDE_BUSY_RUNNERS enabled', () => {
341+
beforeEach(() => {
342+
process.env.INCLUDE_BUSY_RUNNERS = 'true';
343+
});
344+
345+
it('Should not top up when pool size matches runners including busy online runners.', async () => {
346+
// Without INCLUDE_BUSY_RUNNERS: 2 in pool (i-1-idle, i-4-idle-older). With it: 3 (adds i-2-busy).
347+
await adjust({ poolSize: 3 });
348+
expect(createRunners).not.toHaveBeenCalled();
349+
});
350+
351+
it('Should top up by two runners when pool size is 5 and busy runners count toward the pool.', async () => {
352+
await adjust({ poolSize: 5 });
353+
// 3 in pool (idle, busy, older idle); need 2 more
354+
expect(createRunners).toHaveBeenCalledWith(expect.anything(), expect.anything(), 2, expect.anything());
355+
});
356+
});
339357
});

lambdas/functions/control-plane/src/pool/pool.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export async function adjust(event: PoolEvent): Promise<void> {
4747
? validateSsmParameterStoreTags(process.env.SSM_PARAMETER_STORE_TAGS)
4848
: [];
4949
const scaleErrors = JSON.parse(process.env.SCALE_ERRORS) as [string];
50+
const includeBusyRunners = yn(process.env.INCLUDE_BUSY_RUNNERS, { default: false });
5051

5152
const { ghesApiUrl, ghesBaseUrl } = getGitHubEnterpriseApiUrl();
5253

@@ -69,7 +70,7 @@ export async function adjust(event: PoolEvent): Promise<void> {
6970
statuses: ['running'],
7071
});
7172

72-
const numberOfRunnersInPool = calculatePooSize(ec2runners, runnerStatusses);
73+
const numberOfRunnersInPool = calculatePooSize(ec2runners, runnerStatusses, includeBusyRunners);
7374
const topUp = event.poolSize - numberOfRunnersInPool;
7475

7576
if (topUp > 0) {
@@ -123,12 +124,16 @@ async function getInstallationId(ghesApiUrl: string, org: string): Promise<numbe
123124
).data.id;
124125
}
125126

126-
function calculatePooSize(ec2runners: RunnerList[], runnerStatus: Map<string, RunnerStatus>): number {
127+
function calculatePooSize(
128+
ec2runners: RunnerList[],
129+
runnerStatus: Map<string, RunnerStatus>,
130+
includeBusyRunners: boolean,
131+
): number {
127132
// Runner should be considered idle if it is still booting, or is idle in GitHub
128133
let numberOfRunnersInPool = 0;
129134
for (const ec2Instance of ec2runners) {
130135
if (
131-
runnerStatus.get(ec2Instance.instanceId)?.busy === false &&
136+
(runnerStatus.get(ec2Instance.instanceId)?.busy === false || includeBusyRunners) &&
132137
runnerStatus.get(ec2Instance.instanceId)?.status === 'online'
133138
) {
134139
numberOfRunnersInPool++;

main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ module "runners" {
272272
pool_lambda_timeout = var.pool_lambda_timeout
273273
pool_runner_owner = var.pool_runner_owner
274274
pool_lambda_reserved_concurrent_executions = var.pool_lambda_reserved_concurrent_executions
275+
pool_include_busy_runners = var.pool_include_busy_runners
275276

276277
ssm_housekeeper = var.runners_ssm_housekeeper
277278
ebs_optimized = var.runners_ebs_optimized

modules/runners/pool.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module "pool" {
3737
parameter_store_tags = local.parameter_store_tags
3838
}
3939
pool = var.pool_config
40+
include_busy_runners = var.pool_include_busy_runners
4041
role_path = local.role_path
4142
role_permissions_boundary = var.role_permissions_boundary
4243
runner = {

modules/runners/pool/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ resource "aws_lambda_function" "pool" {
4949
ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS = jsonencode(var.config.runner.enable_on_demand_failover_for_errors)
5050
SSM_PARAMETER_STORE_TAGS = var.config.lambda.parameter_store_tags
5151
SCALE_ERRORS = jsonencode(var.config.runner.scale_errors)
52+
INCLUDE_BUSY_RUNNERS = var.config.include_busy_runners
5253
}
5354
}
5455

modules/runners/pool/variables.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ variable "config" {
5757
schedule_expression_timezone = string
5858
size = number
5959
}))
60+
include_busy_runners = bool
6061
role_permissions_boundary = string
6162
kms_key_arn = string
6263
ami_kms_key_arn = string

modules/runners/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,12 @@ variable "pool_config" {
572572
default = []
573573
}
574574

575+
variable "pool_include_busy_runners" {
576+
description = "Include busy runners in the pool calculation. By default busy runners are not included in the pool."
577+
type = bool
578+
default = false
579+
}
580+
575581
variable "disable_runner_autoupdate" {
576582
description = "Disable the auto update of the github runner agent. Be aware there is a grace period of 30 days, see also the [GitHub article](https://github.blog/changelog/2022-02-01-github-actions-self-hosted-runners-can-now-disable-automatic-updates/)"
577583
type = bool

variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,12 @@ variable "pool_config" {
765765
default = []
766766
}
767767

768+
variable "pool_include_busy_runners" {
769+
description = "Include busy runners in the pool calculation. By default busy runners are not included in the pool."
770+
type = bool
771+
default = false
772+
}
773+
768774
variable "aws_partition" {
769775
description = "(optiona) partition in the arn namespace to use if not 'aws'"
770776
type = string

0 commit comments

Comments
 (0)