API 서버에서 특정 로직을 큐로 컨트롤하여 처리하고 있는데, 큐에 많은 부하가 걸려도 동작이 정상적으로 이루어지는지 확인하기 위해 테스트를 하기로 했다. 이 과정에서 다수의 API 요청이 연쇄적으로 이루어져야 하기에 AWS Lambda 함수로 묶고 이를 외부에서 요청하여 다수의 큐 요청을 일괄적으로 컨트롤할 수 있도록 구현하기로 했다.
적절한 권한이 설정된 IAM User 혹은 root User의 access key와 secret access key를 준비해놓는다. IAM User를 만든다면, CloudFormation
, Lambda
, IAMRole
에 대한 권한이 필요하고, 그 이외에는 구현하려는 lambda 기능에 맞게 추가하면 된다.
aws configure
를 실행하여 로그인을 하고, 현재 로그인한 user 정보는 다음의 명령어로 확인가능하다.
lambda % cat ~/.aws/c
config credentials
mkdir lambda && cd lambda
npx cdk init app --language typescript
npm run cdk bootstrap
npm i -D esbuild
cdk는 esbuild를 통해서 타입스크립트 파일을 빌드하기 때문에 따로 설치해줘야한다.
이렇게 실행하고나면 다음과 같은 형태의 프로젝트가 생성된다.
📦
├─ bin
├─ cdk.out
├─ lib
│ └─ app-stack.ts
├─ node_modules
└─ test
├─ cdk.json
├─ package.json
└─ tsconfig.json
먼저 lib 아래에 Lambda 함수의 본체가 되는 핸들러를 작성한다. lib/handler.ts
핸들러를 작성할 때는 반드시 Promise
를 반환하는 함수의 형태로 작성하며, 응답 양식도 정해져있으니 주의가 필요하다.
interface LambdaResponse {
statusCode: number;
headers: Record<string, string>;
body: string;
}
export const handler = async (): Promise<LambdaResponse> => {
try {
// lambda 함수가 실행할 기능
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(result),
}
} catch (error) {
const message = error instanceof Error ? `${error.name}: ${error.message}` : 'Unknown error';
return {
statusCode: 500,
headers: {},
body: message,
}
}
}
handler 작성이 끝났다면, 배포를 위해 stack을 작성해야한다. 이때, 핸들러의 경로와 핸들러 이름 등에 주의한다.
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as path from 'path';
// import * as sqs from 'aws-cdk-lib/aws-sqs';
export class ImageQueueTestStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new cdk.aws_lambda_nodejs.NodejsFunction(this, 'imageQueueTest', {
entry: path.join(__dirname, 'handler.ts'),
handler: 'handler',
});
}
}
작성이 끝났다면 이제 배포를 한다.
npm run cdk deploy
배포한 lambda 함수는 AWS 콘솔에서 직접 테스트해볼 수도 있지만, 함수 URL을 생성하거나 sdk를 이용해서 사용할 수 있다.
만든 Lambda함수를 외부에서 사용하려면 접근하기 위한 URL이 필요하다. 이는 Lambda함수 콘솔에서 Configuration > Function URL에서 만들 수 있다.
아래는 sdk v3를 이용한 예시이다.
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
const imageQueueTest = async () => {
const client = new LambdaClient({
region: 'ap-northeast-2',
});
const command = new InvokeCommand({
FunctionName: 'FuncName',
LogType: 'Tail',
});
const { Payload, LogResult } = await client.send(command);
if (Payload === undefined || LogResult === undefined) {
throw new Error();
}
const result = Buffer.from(Payload).toString();
const logs = Buffer.from(LogResult, 'base64').toString();
return {
result,
logs,
}
}
만약 Lambda함수 실행 중 지연이 있어서 timeout 에러가 발생한다면 timeout 설정을 확인해봐야한다. 해당 Lambda함수의 AWS 콘솔에서 Configuration > General Configuration에서 timeout 설정을 바꿔주자.
기본값이 3초로 들어가있는데 필요한만큼 늘리면 된다.
참고
https://dev.to/kumo/dont-miss-on-the-cloud-revolution-learn-serverless-on-aws-the-right-way-1kac
https://docs.aws.amazon.com/lambda/latest/dg/lambda-typescript.html
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_lambda_code_examples.html