Skip to content

add support for extra env variable #330

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

Open
wants to merge 41 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bcb9938
add tiered param
maxday May 17, 2023
385ffdb
fix manifest
maxday May 17, 2023
975c264
add slug
maxday May 17, 2023
068b4b3
simplify invoker
maxday May 17, 2023
6b0b6a1
prevent tooManyRequestException
maxday May 17, 2023
28f3607
skip add permission
maxday May 17, 2023
f1b380d
skip add permission
maxday May 17, 2023
b864955
skip add permission
maxday May 17, 2023
92addb5
skip add permission
maxday May 17, 2023
a59ac98
better deployer
maxday May 17, 2023
2dd1940
better deployer
maxday May 17, 2023
c7e0279
better deployer
maxday May 17, 2023
4fa91cf
better deployer
maxday May 17, 2023
00aac4a
better deployer
maxday May 17, 2023
a542983
better deployer
maxday May 17, 2023
f07f17c
better deployer
maxday May 17, 2023
407b8ef
better deployer
maxday May 17, 2023
7e3e307
better deployer
maxday May 17, 2023
fd686ba
better deployer
maxday May 17, 2023
6956b41
better deployer
maxday May 17, 2023
8670935
better deployer
maxday May 17, 2023
f1911bb
better deployer
maxday May 17, 2023
655b748
add env
maxday May 17, 2023
934ab77
add env
maxday May 17, 2023
0cefb88
add env
maxday May 17, 2023
e0a167f
add env
maxday May 17, 2023
9cc9745
add env
maxday May 17, 2023
231d88e
update delay
maxday May 18, 2023
66a0b79
update delay
maxday May 18, 2023
a1be047
update delay
maxday May 18, 2023
72ebc37
update delay
maxday May 18, 2023
e6ba67f
update delay
maxday May 18, 2023
183a310
update delay
maxday May 18, 2023
babd690
update delay
maxday May 18, 2023
8ba76d2
update delay
maxday May 18, 2023
fc859ab
update delay
maxday May 18, 2023
17e137e
update delay
maxday May 18, 2023
5208d40
update delay
maxday May 18, 2023
8e6fad2
update delay
maxday May 18, 2023
1590fce
update delay
maxday May 18, 2023
3cae6c9
use event
maxday May 18, 2023
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
210 changes: 137 additions & 73 deletions function-deployer/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,27 @@ const {
const REGION = process.env.AWS_REGION;
const ROLE_ARN = process.env.ROLE_ARN;
const LOG_PROCESSOR_ARN = process.env.LOG_PROCESSOR_ARN;
const PROJECT = `lambda-perf`;
const PROJECT = "lambda-perf";
const MAX_RETRY = 20;

const randomIntFromInterval = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
};

const SHORT_DELAY = randomIntFromInterval(3000, 5000);
const RETRY_DELAY = randomIntFromInterval(25000, 30000);

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const deleteFunction = async (client, functionName) => {
const deleteFunction = async (client, functionName, nbRetry) => {
if (nbRetry > MAX_RETRY) {
throw "max retries exceeded";
}
const params = {
FunctionName: functionName,
};
try {
console.log(`function ${functionName} is about to be deleted`);
const command = new DeleteFunctionCommand(params);
await client.send(command);
console.log(`function ${functionName} deleted`);
Expand All @@ -34,16 +46,17 @@ const deleteFunction = async (client, functionName) => {
console.log(`function ${functionName} does not exist, skipping deletion`);
} else {
console.error(e);
throw e;
await delay(RETRY_DELAY);
await deleteFunction(client, functionName, nbRetry + 1);
}
}
};

async function updateFunction(client, functionName) {
async function updateFunction(client, functionName, environment) {
const params = {
FunctionName: functionName,
Environment: {
Variables: { coldStart: `${Math.random()}` },
Variables: { coldStart: `${Math.random()}`, ...environment },
},
};
try {
Expand All @@ -58,47 +71,55 @@ async function updateFunction(client, functionName) {
const createFunction = async (
client,
functionName,
singleFunction,
path,
handler,
runtime,
memorySize,
architecture
architecture,
environment,
snapStart,
nbRetry
) => {
const sanitizedRuntime = singleFunction.path
? singleFunction.path
: singleFunction.runtime.replace(".", "");
if (nbRetry > MAX_RETRY) {
throw "max retries exceeded";
}
const params = {
FunctionName: functionName,
Handler: singleFunction.handler,
Runtime: singleFunction.runtime,
Handler: handler,
Runtime: runtime,
Code: {
S3Bucket: `${PROJECT}-${REGION}`,
S3Key: `${sanitizedRuntime}/code_${architecture}.zip`,
S3Key: `${path}/code_${architecture}.zip`,
},
Role: ROLE_ARN,
...(singleFunction.snapStart && singleFunction.snapStart),
...snapStart,
MemorySize: memorySize,
Architectures: [architecture],
Environment: {
Variables: environment,
},
};
try {
console.log(
`Creation function ${functionName} for ${architecture} (${memorySize})`
);
const command = new CreateFunctionCommand(params);
await client.send(command);

if (singleFunction.snapStart) {
await waitForActive(client, functionName);

//publish 10 versions
for (let i = 0; i < 10; i++) {
//update variables for publishing new version
await updateFunction(client, functionName);
await delay(10000);
const resp = await publishVersion(client, functionName, 0);
}
}
} catch (e) {
console.error(e);
throw e;
await delay(RETRY_DELAY);
await createFunction(
client,
functionName,
path,
handler,
runtime,
memorySize,
architecture,
environment,
snapStart,
nbRetry + 1
);
}
};

Expand All @@ -108,7 +129,7 @@ const waitForActive = async (client, functionName) => {
console.log(`waiting for function ${functionName} to be active`, func);
while (func.Configuration.State !== "Active") {
console.log(`waiting for function ${functionName} to be active`);
await delay(1000);
await delay(SHORT_DELAY);
func = await getFunction(client, functionName);
}
};
Expand All @@ -126,7 +147,7 @@ const getFunction = async (client, functionName) => {
}
};
const publishVersion = async (client, functionName, nbRetry) => {
if (nbRetry > 5) {
if (nbRetry > MAX_RETRY) {
throw "max retries exceeded";
}
const params = {
Expand All @@ -140,12 +161,15 @@ const publishVersion = async (client, functionName, nbRetry) => {
);
} catch (e) {
console.error(e);
await delay(20000);
await delay(RETRY_DELAY);
await publishVersion(client, functionName, nbRetry + 1);
}
};

const deleteLogGroup = async (client, functionName) => {
const deleteLogGroup = async (client, functionName, nbRetry) => {
if (nbRetry > MAX_RETRY) {
throw "max retries exceeded";
}
const params = {
logGroupName: `/aws/lambda/${functionName}`,
};
Expand All @@ -159,13 +183,16 @@ const deleteLogGroup = async (client, functionName) => {
`loggroup ${params.logGroupName} does not exist, skipping deletion`
);
} else {
console.error(e);
throw e;
await delay(RETRY_DELAY);
await deleteLogGroup(client, functionName, nbRetry + 1);
}
}
};

const createLogGroup = async (client, functionName) => {
const createLogGroup = async (client, functionName, nbRetry) => {
if (nbRetry > MAX_RETRY) {
throw "max retries exceeded";
}
const params = {
logGroupName: `/aws/lambda/${functionName}`,
};
Expand All @@ -174,12 +201,15 @@ const createLogGroup = async (client, functionName) => {
await client.send(command);
console.log(`log group ${params.logGroupName} created`);
} catch (e) {
console.error(e);
throw e;
await delay(RETRY_DELAY);
await createLogGroup(client, functionName, nbRetry + 1);
}
};

const createSubscriptionFilter = async (client, functionName) => {
const createSubscriptionFilter = async (client, functionName, nbRetry) => {
if (nbRetry > MAX_RETRY) {
throw "max retries exceeded";
}
const params = {
destinationArn: LOG_PROCESSOR_ARN,
filterName: `report-log-from-${functionName}`,
Expand All @@ -191,12 +221,15 @@ const createSubscriptionFilter = async (client, functionName) => {
await client.send(command);
console.log(`subscription ${params.filterName} created`);
} catch (e) {
console.error(e);
throw e;
await delay(RETRY_DELAY);
await createSubscriptionFilter(client, functionName, nbRetry + 1);
}
};

const addPermission = async (client, functionName) => {
const addPermission = async (client, functionName, nbRetry) => {
if (nbRetry > MAX_RETRY) {
throw "max retries exceeded";
}
const params = {
FunctionName: functionName,
Action: "lambda:InvokeFunction",
Expand All @@ -209,57 +242,88 @@ const addPermission = async (client, functionName) => {
console.log(`permission added to ${functionName}`);
} catch (e) {
console.error(e);
await delay(RETRY_DELAY);
await addPermission(client, functionName, nbRetry + 1);
}
};

const deploy = async (
lambdaClient,
cloudWatchLogsClient,
path,
slug,
handler,
runtime,
memorySize,
architecture
architecture,
environment,
snapStart
) => {
const runtimes = require("../manifest.json").runtimes;
for (const singleFunction of runtimes) {
if (singleFunction.architectures.includes(architecture)) {
const functionSufix = singleFunction.path
? singleFunction.path
: singleFunction.runtime.replace(".", "");
const functionName = `${PROJECT}-${functionSufix}-${memorySize}-${architecture}`;
try {
await deleteFunction(lambdaClient, functionName);
await createFunction(
lambdaClient,
functionName,
singleFunction,
memorySize,
architecture
);
await deleteLogGroup(cloudWatchLogsClient, functionName);
await createLogGroup(cloudWatchLogsClient, functionName);
await createSubscriptionFilter(cloudWatchLogsClient, functionName);
} catch (e) {
console.error(e);
throw e;
const functionSufix = slug ? slug : path;
const functionName = `${PROJECT}-${functionSufix}-${memorySize}-${architecture}`;
try {
await deleteFunction(lambdaClient, functionName, 0);
await createFunction(
lambdaClient,
functionName,
path,
handler,
runtime,
memorySize,
architecture,
environment,
snapStart,
0
);
if (snapStart) {
await waitForActive(lambdaClient, functionName);

//publish 10 versions
for (let i = 0; i < 10; i++) {
//update variables for publishing new version
await updateFunction(lambdaClient, functionName, environment);
await delay(SHORT_DELAY);
await publishVersion(lambdaClient, functionName, 0);
}
await delay(5000);
} else {
console.log(
`Skipping ${singleFunction.path} as it's not available for ${architecture}`
);
}
await deleteLogGroup(cloudWatchLogsClient, functionName, 0);
await createLogGroup(cloudWatchLogsClient, functionName, 0);
await createSubscriptionFilter(cloudWatchLogsClient, functionName, 0);
} catch (e) {
throw e;
}
};

exports.handler = async (_, context) => {
exports.handler = async (event, context) => {
try {
console.log("clientContext = ", context.clientContext);
const { memorySize, architecture } = context.clientContext;
console.log("event = ", event);
const {
memorySize,
architecture,
path,
slug,
handler,
runtime,
environment,
snapStart,
} = event;
const lambdaClient = new LambdaClient({ region: REGION });
const cloudWatchLogsClient = new CloudWatchLogsClient({
region: REGION,
});
await addPermission(lambdaClient, LOG_PROCESSOR_ARN);
await deploy(lambdaClient, cloudWatchLogsClient, memorySize, architecture);
//await addPermission(lambdaClient, LOG_PROCESSOR_ARN);
await deploy(
lambdaClient,
cloudWatchLogsClient,
path,
slug,
handler,
runtime,
memorySize,
architecture,
environment,
snapStart
);
return {
statusCode: 200,
body: JSON.stringify("success"),
Expand Down
Loading