Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lambda): reuse http clients #3931

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions lambdas/functions/ami-housekeeper/src/ami.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { createChildLogger } from '@terraform-aws-github-runner/aws-powertools-u
import { getTracedAWSV3Client } from '@terraform-aws-github-runner/aws-powertools-util';

const logger = createChildLogger('ami');
const ec2Client = getTracedAWSV3Client(new EC2Client({}));
const ssmClient = getTracedAWSV3Client(new SSMClient({}));

export interface AmiCleanupOptions {
minimumDaysOld?: number;
Expand Down Expand Up @@ -83,7 +85,6 @@ async function getAmisNotInUse(options: AmiCleanupOptions) {
const amiIdsInSSM = await getAmisReferedInSSM(options);
const amiIdsInTemplates = await getAmiInLatestTemplates(options);

const ec2Client = getTracedAWSV3Client(new EC2Client({}));
logger.debug('Getting all AMIs from ec2 with filters', { filters: options.amiFilters });
const amiEc2 = await ec2Client.send(
new DescribeImagesCommand({
Expand Down Expand Up @@ -134,7 +135,6 @@ async function deleteAmi(amiDetails: Image, options: AmiCleanupOptionsInternal):

try {
logger.info(`deleting ami ${amiDetails.Name || amiDetails.ImageId} created at ${amiDetails.CreationDate}`);
const ec2Client = getTracedAWSV3Client(new EC2Client({}));
await ec2Client.send(new DeregisterImageCommand({ ImageId: amiDetails.ImageId, DryRun: options.dryRun }));
await deleteSnapshot(options, amiDetails, ec2Client);
} catch (error) {
Expand All @@ -159,7 +159,6 @@ async function deleteSnapshot(options: AmiCleanupOptions, amiDetails: Image, ec2
}

async function getAmiInLatestTemplates(options: AmiCleanupOptions): Promise<(string | undefined)[]> {
const ec2Client = getTracedAWSV3Client(new EC2Client({}));
const launnchTemplates = await ec2Client.send(
new DescribeLaunchTemplatesCommand({
LaunchTemplateNames: options.launchTemplateNames,
Expand Down Expand Up @@ -189,7 +188,6 @@ async function getAmisReferedInSSM(options: AmiCleanupOptions): Promise<(string
return [];
}

const ssmClient = getTracedAWSV3Client(new SSMClient({}));
const ssmParams = await ssmClient.send(
new DescribeParametersCommand({
ParameterFilters: [
Expand Down
6 changes: 2 additions & 4 deletions lambdas/functions/control-plane/src/aws/runners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ScaleError from './../scale-runners/ScaleError';
import * as Runners from './runners.d';

const logger = createChildLogger('runners');
const ec2 = getTracedAWSV3Client(new EC2Client({ region: process.env.AWS_REGION }));

interface Ec2Filter {
Name: string;
Expand Down Expand Up @@ -57,7 +58,6 @@ function constructFilters(filters?: Runners.ListRunnerFilters): Ec2Filter[][] {
}

async function getRunners(ec2Filters: Ec2Filter[]): Promise<Runners.RunnerList[]> {
const ec2 = getTracedAWSV3Client(new EC2Client({ region: process.env.AWS_REGION }));
const runners: Runners.RunnerList[] = [];
let nextToken;
let hasNext = true;
Expand Down Expand Up @@ -94,7 +94,6 @@ function getRunnerInfo(runningInstances: DescribeInstancesResult) {
}

export async function terminateRunner(instanceId: string): Promise<void> {
const ec2 = getTracedAWSV3Client(new EC2Client({ region: process.env.AWS_REGION }));
await ec2.send(new TerminateInstancesCommand({ InstanceIds: [instanceId] }));
logger.info(`Runner ${instanceId} has been terminated.`);
}
Expand Down Expand Up @@ -127,10 +126,9 @@ export async function createRunner(runnerParameters: Runners.RunnerInputParamete
},
});

const ec2Client = getTracedAWSV3Client(new EC2Client({ region: process.env.AWS_REGION }));
const amiIdOverride = await getAmiIdOverride(runnerParameters);

const fleet: CreateFleetResult = await createInstances(runnerParameters, amiIdOverride, ec2Client);
const fleet: CreateFleetResult = await createInstances(runnerParameters, amiIdOverride, ec2);

const instances: string[] = await processFleetResult(fleet, runnerParameters);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { DeleteParameterCommand, GetParametersByPathCommand, SSMClient } from '@aws-sdk/client-ssm';
import { logger } from '@terraform-aws-github-runner/aws-powertools-util';
import { getTracedAWSV3Client } from '@terraform-aws-github-runner/aws-powertools-util';
import { getTracedAWSV3Client, logger } from '@terraform-aws-github-runner/aws-powertools-util';

export interface SSMCleanupOptions {
dryRun: boolean;
minimumDaysOld: number;
tokenPath: string;
}

const client = getTracedAWSV3Client(new SSMClient({ region: process.env.AWS_REGION }));

function validateOptions(options: SSMCleanupOptions): void {
const errorMessages: string[] = [];
if (!options.minimumDaysOld || options.minimumDaysOld < 1) {
Expand All @@ -26,7 +27,6 @@ export async function cleanSSMTokens(options: SSMCleanupOptions): Promise<void>
logger.debug('Cleaning with options', { options });
validateOptions(options);

const client = getTracedAWSV3Client(new SSMClient({ region: process.env.AWS_REGION }));
const parameters = await client.send(new GetParametersByPathCommand({ Path: options.tokenPath }));
while (parameters.NextToken) {
const nextParameters = await client.send(
Expand Down
5 changes: 2 additions & 3 deletions lambdas/functions/gh-agent-syncer/src/syncer/syncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Stream } from 'stream';
const versionKey = 'name';

const logger = createChildLogger('syncer.ts');
const githubClient = new Octokit();
const s3 = getTracedAWSV3Client(new S3Client({}));

interface CacheObject {
bucket: string;
Expand Down Expand Up @@ -36,7 +38,6 @@ interface ReleaseAsset {
}

async function getReleaseAsset(runnerOs = 'linux', runnerArch = 'x64'): Promise<ReleaseAsset | undefined> {
const githubClient = new Octokit();
const latestRelease = await githubClient.repos.getLatestRelease({
owner: 'actions',
repo: 'runner',
Expand Down Expand Up @@ -85,8 +86,6 @@ async function uploadToS3(
}

export async function sync(): Promise<void> {
const s3 = getTracedAWSV3Client(new S3Client({}));

const runnerOs = process.env.GITHUB_RUNNER_OS || 'linux';
const runnerArch = process.env.GITHUB_RUNNER_ARCHITECTURE || 'x64';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { Config } from './ConfigResolver';
import { MetricUnits } from '@aws-lambda-powertools/metrics';

const logger = createChildLogger('termination-warning');
const ec2 = getTracedAWSV3Client(new EC2Client({ region: process.env.AWS_REGION }));

async function handle(event: SpotInterruptionWarning<SpotTerminationDetail>, config: Config): Promise<void> {
logger.debug('Received spot notification warning:', { event });
const ec2 = getTracedAWSV3Client(new EC2Client({ region: process.env.AWS_REGION }));
const instance =
(await ec2.send(new DescribeInstancesCommand({ InstanceIds: [event.detail['instance-id']] }))).Reservations?.[0]
.Instances?.[0] ?? null;
Expand Down
6 changes: 4 additions & 2 deletions lambdas/libs/aws-ssm-util/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { GetParameterCommand, PutParameterCommand, SSMClient, Tag } from '@aws-sdk/client-ssm';
import { getTracedAWSV3Client } from '@terraform-aws-github-runner/aws-powertools-util';

let ssmClient: SSMClient;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is a lib, I don't want to create a new client on import, so we're caching a client only when the below functions are called;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, the caller should pass in a client


export async function getParameter(parameter_name: string): Promise<string> {
const client = getTracedAWSV3Client(new SSMClient({ region: process.env.AWS_REGION }));
const client = getTracedAWSV3Client((ssmClient ??= new SSMClient({ region: process.env.AWS_REGION })));
return (await client.send(new GetParameterCommand({ Name: parameter_name, WithDecryption: true }))).Parameter
?.Value as string;
}
Expand All @@ -13,7 +15,7 @@ export async function putParameter(
secure: boolean,
options: { tags?: Tag[] } = {},
): Promise<void> {
const client = getTracedAWSV3Client(new SSMClient({ region: process.env.AWS_REGION }));
const client = getTracedAWSV3Client((ssmClient ??= new SSMClient({ region: process.env.AWS_REGION })));
await client.send(
new PutParameterCommand({
Name: parameter_name,
Expand Down
Loading