Node.js에서 Lambda 함수 핸들러 정의 - AWS Lambda

Node.js에서 Lambda 함수 핸들러 정의

Lambda 함수의 핸들러는 이벤트를 처리하는 함수 코드의 메서드입니다. 함수가 호출되면 Lambda는 핸들러 메서드를 실행합니다. 함수는 핸들러가 응답을 반환하거나 종료하거나 제한 시간이 초과될 때까지 실행됩니다.

Node.js 핸들러 기본 사항

다음 예제 함수는 이벤트 객체의 내용을 로깅하고 로그의 위치를 반환합니다.

참고

이 페이지에서는 CommonJS 및 ES 모듈 핸들러의 예를 보여줍니다. 이 두 핸들러 유형의 차이에 대해 자세히 알아보려면 함수 핸들러를 ES 모듈로 지정을 참조하세요.

ES module handler
export const handler = async (event, context) => { console.log("EVENT: \n" + JSON.stringify(event, null, 2)); return context.logStreamName; };
CommonJS module handler
exports.handler = async function (event, context) { console.log("EVENT: \n" + JSON.stringify(event, null, 2)); return context.logStreamName; };

함수를 구성할 때, 핸들러 설정의 값은 파일의 이름과 내보낸 핸들러 모듈의 이름이며 점으로 구분됩니다. 콘솔의 기본값은 예를 들어, 이 가이드에서는 index.handler입니다. 이는 handler 파일에서 내보낸 index.js 메서드를 나타냅니다.

런타임은 인수를 핸들러 메서드에 전달합니다. 첫 번째 인수는 호출자로부터의 정보가 포함된 event 객체입니다. 이 정보는 Invoke를 호출할 때 호출자가 JSON 형식 문자열로 전달하고, 런타임은 이 졍보를 객체로 변환합니다. AWS 서비스가 함수를 호출할 때, 이벤트 구조는 서비스별로 다릅니다.

두 번째 인수는 컨텍스트 객체이며, 여기에는 호출, 함수 및 실행 환경에 대한 정보가 포함되어 있습니다. 이전 예제에서는, 함수가 컨텍스트 객체로부터 로그 스트림의 이름을 가져와서 호출자에게 반환합니다.

응답을 전송하기 위해 비동기 핸들러에서 호출할 수 있는 함수인 콜백 인수를 사용할 수도 있습니다. 콜백 대신 비동기/대기를 사용하는 것이 좋습니다. 비동기/대기는 향상된 가독성, 오류 처리 및 효율성을 제공합니다. 비동기/대기 및 콜백 간의 차이에 대한 더 자세한 내용은 콜백 사용을 참조하십시오.

이름 지정

함수를 구성할 때, 핸들러 설정의 값은 파일의 이름과 내보낸 핸들러 모듈의 이름이며 점으로 구분됩니다. 콘솔에서 생성된 함수의 기본값은 예를 들어, 이 가이드에서는 index.handler입니다. 이는 index.js 또는 index.mjs 파일에서 내보낸 handler 메서드를 나타냅니다.

콘솔에서 다른 파일 이름 또는 함수 핸들러 이름을 사용하여 함수를 생성하는 경우 기본 핸들러 이름을 편집해야 합니다.

함수 핸들러 이름 변경(콘솔)
  1. Lambda 콘솔의 함수 페이지를 열고 함수를 선택합니다.

  2. Code(코드) 탭을 선택합니다.

  3. 아래로 스크롤하여 런타임 설정 창으로 이동한 다음 편집을 선택합니다.

  4. 핸들러에서 함수 핸들러의 새 이름을 입력합니다.

  5. Save(저장)를 선택합니다.

비동기/대기 사용

비동기식 작업을 수행하는 코드의 경우, 동기/대기 패턴을 사용하여 핸들러 실행을 완료하세요. 비동기/대기는 중첩된 콜백이나 체인 프라미스 없이 Node.js 내에서 비동기 코드를 작성할 수 있는 간결하고 읽기 쉬운 방법입니다. 비동기/대기를 사용하면 비동기 및 비차단 상태를 유지하면서 동기 코드처럼 읽는 코드를 작성할 수 있습니다.

async 키워드는 함수를 비동기로 표시하고 await 키워드는 Promise이 해결될 때까지 함수 실행을 일시 중지합니다.

참고

비동기 이벤트가 완료될 때까지 기다려야 합니다. 비동기 이벤트가 완료되기 전에 함수가 반환되면 함수가 실패하거나 애플리케이션에서 예상치 못한 동작이 발생할 수 있습니다. 이는 forEach 루프에 비동기 이벤트가 포함되어 있을 때 발생할 수 있습니다. forEach 루프에는 동기 호출이 필요합니다. 자세한 내용은 Mozilla 설명서의 Array.prototype.forEach()를 참조하세요.

ES module handler
예 – async/await로 HTTP 요청
const url = "https://aws.amazon.com/"; export const handler = async(event) => { try { // fetch is available in Node.js 18 and later runtimes const res = await fetch(url); console.info("status", res.status); return res.status; } catch (e) { console.error(e); return 500; } };
CommonJS module handler
예 – async/await로 HTTP 요청
const https = require("https"); let url = "https://aws.amazon.com/"; exports.handler = async function (event) { let statusCode; await new Promise(function (resolve, reject) { https.get(url, (res) => { statusCode = res.statusCode; resolve(statusCode); }).on("error", (e) => { reject(Error(e)); }); }); console.log(statusCode); return statusCode; };

다음 예에서는 비동기/대기를 사용하여 Amazon Simple Storage Service 버킷을 나열합니다.

참고

이 예제를 사용하기 전에 함수의 실행 역할에 Amazon S3 읽기 권한이 있는지 확인하십시오.

ES module handler
예 — 비동기/대기 기능이 있는 AWS SDK v3

이 예제에서는 nodejs18.x 이상 런타임에서 사용할 수 있는 AWS SDK for JavaScript v3를 사용합니다.

import {S3Client, ListBucketsCommand} from '@aws-sdk/client-s3'; const s3 = new S3Client({region: 'us-east-1'}); export const handler = async(event) => { const data = await s3.send(new ListBucketsCommand({})); return data.Buckets; };
CommonJS module handler
예 — 비동기/대기 기능이 있는 AWS SDK v3

이 예제에서는 nodejs18.x 이상 런타임에서 사용할 수 있는 AWS SDK for JavaScript v3를 사용합니다.

const { S3Client, ListBucketsCommand } = require('@aws-sdk/client-s3'); const s3 = new S3Client({ region: 'us-east-1' }); exports.handler = async (event) => { const data = await s3.send(new ListBucketsCommand({})); return data.Buckets; };

콜백 사용

콜백을 사용하는 대신 비동기/대기를 사용하여 함수 핸들러를 선언하는 것이 좋습니다. 비동기/대기는 다음과 같은 여러 가지 이유로 더 나은 선택입니다.

  • 가독성: 비동기/대기 코드는 콜백 코드보다 읽기 쉽고 이해하기 쉬우므로 따르기가 금방 어려워지고 콜백 문제가 발생할 수 있습니다.

  • 디버깅 및 오류 처리: 콜백 기반 코드를 디버깅하는 것은 어려울 수 있습니다. 콜 스택은 추적하기 어려워지고 오류는 쉽게 삼킬 수 있습니다. 비동기/대기를 사용하면 try/catch 블록을 사용하여 오류를 처리할 수 있습니다.

  • 효율성: 콜백은 종종 코드의 다른 부분을 전환해야 합니다. 비동기/대기는 컨텍스트 전환 수를 줄여 코드 효율성을 높일 수 있습니다.

핸들러에서 콜백을 사용하는 경우, 이벤트 루프가 비어 있거나 함수 제한 시간을 초과할 때까지 함수가 계속 실행됩니다. 응답은 모든 이벤트 루프 작업이 완료될 때까지 호출자에게 전송되지 않습니다. 함수 제한 시간을 초과하면, 대신 오류가 반환됩니다. context.callbackWaitsForEmptyEventLoop를 false로 설정하여 즉시 응답을 전송하도록 런타임을 구성할 수 있습니다.

콜백 함수는 두 개의 인수, Error 및 응답을 사용합니다. 응답 객체는 JSON.stringify와 호환되어야 합니다.

다음 예제 함수는 URL을 확인하고 상태 코드를 호출자에게 반환합니다.

ES module handler
예 – callback으로 HTTP 요청
import https from "https"; let url = "https://aws.amazon.com/"; export function handler(event, context, callback) { https.get(url, (res) => { callback(null, res.statusCode); }).on("error", (e) => { callback(Error(e)); }); }
CommonJS module handler
예 – callback으로 HTTP 요청
const https = require("https"); let url = "https://aws.amazon.com/"; exports.handler = function (event, context, callback) { https.get(url, (res) => { callback(null, res.statusCode); }).on("error", (e) => { callback(Error(e)); }); };

아래 예제에서는, Amazon S3로부터의 응답이 사용 가능해지는 즉시 호출자에게 반환됩니다. 이벤트 루프에서 실행 중인 제한 시간은 동결되고 다음에 함수가 호출될 때 계속 실행됩니다.

참고

이 예제를 사용하기 전에 함수의 실행 역할에 Amazon S3 읽기 권한이 있는지 확인하십시오.

ES module handler
예 — callbackWaitsForEmptyEventLoop 기능이 있는 AWS SDK v3

이 예제에서는 nodejs18.x 이상 런타임에서 사용할 수 있는 AWS SDK for JavaScript v3를 사용합니다.

import AWS from "@aws-sdk/client-s3"; const s3 = new AWS.S3({}); export const handler = function (event, context, callback) { context.callbackWaitsForEmptyEventLoop = false; s3.listBuckets({}, callback); setTimeout(function () { console.log("Timeout complete."); }, 5000); };
CommonJS module handler
예 — callbackWaitsForEmptyEventLoop 기능이 있는 AWS SDK v3

이 예제에서는 nodejs18.x 이상 런타임에서 사용할 수 있는 AWS SDK for JavaScript v3를 사용합니다.

const AWS = require("@aws-sdk/client-s3"); const s3 = new AWS.S3({}); exports.handler = function (event, context, callback) { context.callbackWaitsForEmptyEventLoop = false; s3.listBuckets({}, callback); setTimeout(function () { console.log("Timeout complete."); }, 5000); };

Node.js Lambda 함수의 코드 모범 사례

Lambda 함수를 구축할 때 코딩 모범 사례를 사용하려면 다음 목록의 지침을 준수하세요.

  • 핵심 로직에서 Lambda 핸들러를 분리합니다. 이를 통해 단위 테스트를 수행할 수 있는 더 많은 함수를 만들 수 있습니다. Node.js에서 이는 다음과 같을 수 있습니다.

    exports.myHandler = function(event, context, callback) { var foo = event.foo; var bar = event.bar; var result = MyLambdaFunction (foo, bar); callback(null, result); } function MyLambdaFunction (foo, bar) { // MyLambdaFunction logic here }
  • 함수 배포 패키지의 종속성을 제어합니다. AWS Lambda 실행 환경에는 여러 라이브러리가 포함되어 있습니다. Node.js 및 Python 런타임의 경우, 여기에는 AWS SDK가 포함됩니다. 최신 기능 및 보안 업데이트를 활성화하려면 Lambda가 주기적으로 이러한 라이브러리를 업데이트해야 합니다. 이러한 업데이트는 Lambda 함수의 동작에 사소한 변화를 가져올 수 있습니다. 함수가 사용하는 종속성을 완전히 제어하려면 모든 종속성을 배포 패키지로 패키징하세요.

  • 종속성의 복잡성을 최소화합니다. 실행 환경 시작 시 빠르게 로드되는 더 단순한 프레임워크가 권장됩니다.

  • 배포 패키지 크기를 런타임 필요에 따라 최소화합니다. 이렇게 하면 호출 전에 배포 패키지를 다운로드하고 압축을 풀 때 걸리는 시간이 단축됩니다.

  • 실행 환경 재사용을 활용하여 함수 성능을 향상시킵니다. 함수 핸들러 외부에서 SDK 클라이언트 및 데이터베이스 연결을 초기화하고 정적 자산을 /tmp 디렉토리에 로컬로 캐시합니다. 동일한 함수 인스턴스에서 처리하는 후속 호출은 이러한 리소스를 재사용할 수 있습니다. 이를 통해 함수 실행 시간을 줄여 비용을 절감합니다.

    호출에서 발생할 수 있는 데이터 유출을 방지하려면 실행 환경을 사용하여 사용자 데이터, 이벤트 또는 보안과 관련된 기타 정보를 저장하지 마세요. 함수가 핸들러 내부 메모리에 저장할 수 없는 변경 가능한 상태에 의존하는 경우 각 사용자에 대해 별도의 함수 또는 별도의 함수 버전을 생성하는 것이 좋습니다.

  • 연결 유지 지시문을 사용하여 지속적인 연결을 유지하세요. Lambda는 시간이 지남에 따라 유휴 연결을 제거합니다. 함수를 호출할 때 유휴 연결을 재사용하려고 하면 연결 오류가 발생합니다. 지속적인 연결을 유지하려면 런타임과 관련된 연결 유지 지시문을 사용하세요. 예를 들어, Node.js에서 연결 유지를 이용해 연결 재사용을 참조하세요.

  • 환경 변수를 사용하여 함수에 운영 파라미터를 전달합니다. 예를 들어, Amazon S3 버킷에 기록하는 경우 기록하고 있는 버킷 이름을 하드 코딩하는 대신 환경 변수로 구성합니다.

  • 일부 임의 기준이 충족될 때까지 함수가 자동으로 자체 호출이 되는 리커시브 코드를 Lambda 함수에서 사용하지 않도록 합니다. 리커시브 코드를 사용할 경우, 의도하지 않은 함수 호출이 증가하고 비용이 상승할 수 있습니다. 실수로 그렇게 한 경우 코드를 업데이트하는 동안 즉시 함수 예약된 동시성을 0으로 설정하여 해당 함수에 대한 모든 호출을 조절합니다.

  • Lambda 함수 코드에는 문서화되지 않은 비공개 API를 사용하지 마세요. AWS Lambda 관리형 런타임의 경우, Lambda는 주기적으로 보안 및 기능 업데이트를 Lambda의 내부 API에 적용합니다. 이러한 내부 API 업데이트는 이전 버전과 호환되지 않으므로 함수가 이러한 비공개 API에 종속성을 갖는 경우 호출 실패와 같은 의도하지 않은 결과를 초래할 수 있습니다. 공개적으로 사용 가능한 API의 목록은 API 레퍼런스를 참조하세요.

  • 멱등성 코드를 작성합니다. 함수에 멱등성 코드를 작성하면 중복 이벤트가 동일한 방식으로 처리됩니다. 코드는 이벤트를 올바르게 검증하고 중복 이벤트를 정상적으로 처리해야 합니다. 자세한 내용은 멱등성 Lambda 함수를 만들려면 어떻게 해야 합니까? 단원을 참조하십시오.