Serverless Framework Plugin์ ๋ง๋ค์ด์ Lambda timeout ์ก์๋ด๊ธฐ
- #Serverless Framework
- #lambda
- #plugin
- #timeout
Serverless Framework Plugin ๋ง๋ค๊ธฐ
์๋ ํ์ธ์. ์๋์/ํ๋กฌ ๋ฐฑ์๋ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๊ณ ์๋ ์ ๊ทผ์๋ผ๊ณ ํฉ๋๋ค.
์ ํฌ ๋ฐฑ์๋ํ์ ๋ง์ ๋ถ๋ถ์์ Serverless Framework๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
Serverless Framework์ ๋ถ์ฌ์ ์ธ ์ ์๋ plugin๋ค์ด ๋ง์ด ์๋๋ฐ, ์ด๋ฒ์๋ ํ์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ plugin์ ์ฐพ์ง ๋ชปํด์, ๊ฐ๋จํ plugin์ ๋ง๋ค์๋๋ฐ, ๊ทธ ๊ณผ์ ์ ๊ณต์ ํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
Serverless Framework๋?
Serverless Framework๋ ์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ๋ฅผ ์ฝ๊ฒ ๊ตฌ์ฑํ๊ณ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๋๊ตฌ์ ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก๋ API Gateway์ Lambda๋ฅผ ์ด์ฉํด์ ์ฝ๊ฒ API ์๋ฒ๋ฅผ ๋ง๋ค๊ณ ๊ด๋ฆฌํ ์ ์๊ณ , ๊ทธ ์ธ์ ํ์ํ AWS ๊ตฌ์ฑ์์๋ค๋ IaC ํํ๋ก ์ถ๊ฐ๋ก ๊ด๋ฆฌํ ์๋ ์์ต๋๋ค.
๋ง๋ค๊ฒ ๋ ๋ฐฐ๊ฒฝ
์ ํฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก๋ Serverless Framework๋ฅผ API ์๋ฒ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ์ฉ๋๋ก ์ฌ์ฉํ์ง๋ง, SQS๋ฅผ ๋ง๋ค๊ณ SQS ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ Lambda function์ ๊ด๋ฆฌํ๋ ์ฉ๋๋ก๋ ๋ง์ด ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
SQS์ ๋ถ์ธ Lambda function์ด ์ค๋ฅ๊ฐ ๋์ throw๋ ๊ฒฝ์ฐ์๋, ์๋์ผ๋ก ์ฌ์๋๋๊ฒ๋ ์ค์ ํด์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
ํ์ง๋ง Lambda function์ด timeout์ด ๋ ๊ฒฝ์ฐ์๋, throw๋ก ์ฒ๋ฆฌ๋์ง ์๊ธฐ๋๋ฌธ์ ์ฌ์๋ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์๊ฒ ๋ฉ๋๋ค.
์ด๋ ๊ฒ Lambda๊ฐ timeout์ด ๋ ๊ฒฝ์ฐ, ๋ฐ๋ก ๋ชจ๋ํฐ๋ง์ ํ๊ณ ์์ง ์์์ ๋์น๊ฒ ๋๋ ๊ฒฝ์ฐ๊ฐ ์๊ฒจ์,
์ด ๋ถ๋ถ์ Serverless Framework์ plugin์ผ๋ก ๋ง๋ค์ด๋ณด๊ฒ ๋์์ต๋๋ค.
Lambda timeout ์ด๋ฒคํธ ์๋ ์ค์
Lambda๊ฐ timeout์ผ๋ก ์ข
๋ฃ๋ ๋, Cloudwatch Logs์ Task timed out after
๋ผ๋ ํน์ ํ ๋ฉ์์ง๋ฅผ ๋จ๊ธฐ๋ฉด์ ์ข
๋ฃ๋ฉ๋๋ค.
Cloudwatch Logs์ ์ ๋ฉ์์ง๋ฅผ ํํฐํ๊ณ , ํด๋น ๋ฉํธ๋ฆญ์ ์๋์ ์ค์ ํ๋ ํํ๋ก ๊ตฌ์ฑํ๋ฉด,
Lambda์ timeout ์๋ฆผ์ ๋ฐ์ ์ ์์ต๋๋ค.
plugin ๋ง๋ค๊ธฐ
Serverless Framework ๊ณต์ ๋ฌธ์์ plugin์ ๋ง๋๋ ๋ฐฉ๋ฒ์ด ๊ฐ๋จํ๊ฒ ์๊ฐ๋์ด ์์ต๋๋ค.
๊ฐ๋จํ ์์ ๋ฅผ ๋ง๋ค๊ธฐ์๋ ์ถฉ๋ถํ์ง๋ง, ์์ธํ๊ฒ ๋ด์ฉ์ด ๋์์์ง ์์์, ์ด ๋ธ๋ก๊ทธ ๋ด์ฉ์ ์ฐธ๊ณ ํด์ ๋ง๋ค์์ต๋๋ค.
constructor์์๋ aws sdk ์์ฒญ์ ์ํ provider์ Serverless Framework์ hook์ ์ค์ ํฉ๋๋ค.
(hook์ handler๋ async function์ ์ง์ํฉ๋๋ค ๐)
constructor(serverless) {
this.#serverless = serverless;
this.#provider = this.#serverless.getProvider(this.#serverless.service.provider.name);
this.hooks = {
'after:deploy:deploy': () => this.afterDeploy()
};
}
์ค์ ๋ก์ง์ hook์ ์ค์ ํด๋ afterDeploy() ๋ฉ์๋์์ ์คํํฉ๋๋ค.
provider request์์ฒญ์ CloudFormation ์์ฒญ์ ์ฐธ๊ณ ํด์ ๊ตฌ์ฑํ๋ฉด ๋ฉ๋๋ค.
async afterDeploy() {
console.log('๐ after:deploy:deploy');
for (const func of Object.values(this.#serverless.service.functions)) {
console.log(`๐พ ${func.name}`);
console.log(
await this.#provider.request('CloudWatchLogs', 'putMetricFilter', {
logGroupName: `/aws/lambda/${func.name}`,
filterName: 'lambda-timeout',
filterPattern: 'Task timed out after', // ๋๋ค ํ์์์ ๋ฐ์ํ์๋ ์ฐํ๋ ๋ก๊ทธ
metricTransformations: [
{
metricNamespace: 'Fromm/LambdaTimeouts',
metricName: func.name,
metricValue: '1'
}
]
})
);
console.log(
await this.#provider.request('CloudWatch', 'putMetricAlarm', {
AlarmName: `LambdaTimeoutAlarm - ${func.name}`,
Namespace: 'Fromm/LambdaTimeouts',
MetricName: func.name,
Period: 10, // ์ด ๋จ์ ๊ฐ๊ฒฉ
EvaluationPeriods: 1, // ํ๋์ ์๋์ด ๋ฐ์ํ๋ ค๋ฉด ํ๊ฐํ๋ ๊ธฐ๊ฐ์ ์
Threshold: 1, // ์๋์ด ๋ฐ์ํ๋ ์๊ณ๊ฐ
ComparisonOperator: 'GreaterThanOrEqualToThreshold', // ์๊ณ๊ฐ ์กฐ๊ฑด
Statistic: 'Minimum',
AlarmActions: ['arn:aws:sns:ap-northeast-2:xxxxxxxx:LambdaTimeoutTopic'], // ์๋ ๋ฐ์ ์ SNS ์ฃผ์ ๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋
๋๋ค
OKActions: [], // ์๋์ด ํด์ ๋ ๋ ์คํ๋๋ ์์
InsufficientDataActions: [], // ๋ฐ์ดํฐ๊ฐ ์ถฉ๋ถํ์ง ์์ ๊ฒฝ์ฐ ์คํ๋๋ ์์
TreatMissingData: 'missing' // ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ 'missing'์ผ๋ก ์ค์ ํ์ฌ ๊ฒฝ๊ณ ๋ฅผ ๋ฐฉ์งํฉ๋๋ค
})
);
}
}
์ ์ฒด ์ฝ๋๋ ์๋์ ๊ฐ์ต๋๋ค.
'use strict';
class TimeoutPlugin {
#serverless;
#provider;
constructor(serverless) {
// .... ์์ ๋ด์ฉ๊ณผ ๊ฐ์ต๋๋ค.
}
async afterDeploy() {
// .... ์์ ๋ด์ฉ๊ณผ ๊ฐ์ต๋๋ค.
}
}
module.exports = TimeoutPlugin;
๊ทธ๋ฆฌ๊ณ serverless.yml์ plugins ํญ๋ชฉ์ ์ถ๊ฐํด์ค๋๋ค.
service: app
functions:
# ...
plugins:
- ./timeout_plugin.js
๋ง๋ฌด๋ฆฌ
์ด์ ๋ง๋ค์ด์ง SNS ํ ํฝ์ ์ฒ๋ฆฌํ Lambda function์ ๋ง๋ค๊ณ , ์ฌ๋ ์๋ฆผ ๋ฑ์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ๋๋ค์ timeout ์๋ฆผ์ ๋ฐ์ ์ ์์ต๋๋ค.
๊ฐ๋จํ ๊ธฐ๋ฅ์ด์์ง๋ง, ๋ฌธ์๋ ๊ฐ๋จํ๊ฒ๋ง ๋์์์ด์ ์๋ฃ๋ฅผ ์ฐพ๋๋ผ ์๊ฐ๋ณด๋ค ์๊ฐ์ด ๊ฑธ๋ ธ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋๊น์ง ์ฝ์ด์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค~ ๐