Python에서 Lambda 함수 핸들러 정의

Python에서 Lambda 함수 핸들러 정의 (Define Lambda function handler in Python)

Lambda 함수 핸들러(handler)는 이벤트를 처리하는 함수 코드의 메서드예요. 함수가 호출되면 Lambda는 핸들러 메서드를 실행해요. 함수는 핸들러가 응답을 반환하거나, 종료되거나, 타임아웃될 때까지 실행돼요.

출처: AWS Lambda 개발자 안내서

본문

이 페이지는 이름 규칙, 유효한 핸들러 시그니처, 코드 모범 사례를 포함해 Python에서 Lambda 함수 핸들러로 작업하는 방법을 설명해요. 이 페이지에는 주문 정보를 받아 텍스트 파일 영수증을 생성하고 이 파일을 Amazon Simple Storage Service(Amazon S3) 버킷에 넣는 Python Lambda 함수 예제도 포함돼 있어요.

예제 Python Lambda 함수 코드 (Example Python Lambda function code)

다음 예제 Python Lambda 함수 코드는 주문 정보를 받아 텍스트 파일 영수증을 생성하고 이 파일을 Amazon S3 버킷에 넣어요.

예제 Python Lambda 함수

import json
import os
import logging
import boto3

# Initialize the S3 client outside of the handler
s3_client = boto3.client('s3')

# Initialize the logger
logger = logging.getLogger()
logger.setLevel("INFO")

def upload_receipt_to_s3(bucket_name, key, receipt_content):
    """Helper function to upload receipt to S3"""

    try:
        s3_client.put_object(
            Bucket=bucket_name,
            Key=key,
            Body=receipt_content
        )
    except Exception as e:
        logger.error(f"Failed to upload receipt to S3: {str(e)}")
        raise

def lambda_handler(event, context):
    """
    Main Lambda handler function
    Parameters:
        event: Dict containing the Lambda function event data
        context: Lambda runtime context
    Returns:
        Dict containing status message
    """
    try:
        # Parse the input event
        order_id = event['Order_id']
        amount = event['Amount']
        item = event['Item']

        # Access environment variables
        bucket_name = os.environ.get('RECEIPT_BUCKET')
        if not bucket_name:
            raise ValueError("Missing required environment variable RECEIPT_BUCKET")

        # Create the receipt content and key destination
        receipt_content = (
            f"OrderID: {order_id}\n"
            f"Amount: ${amount}\n"
            f"Item: {item}"
        )
        key = f"receipts/{order_id}.txt"

        # Upload the receipt to S3
        upload_receipt_to_s3(bucket_name, key, receipt_content)

        logger.info(f"Successfully processed order {order_id} and stored receipt in S3 bucket {bucket_name}")

        return {
            "statusCode": 200,
            "message": "Receipt processed successfully"
        }

    except Exception as e:
        logger.error(f"Error processing order: {str(e)}")
        raise

이 파일에는 다음 코드 섹션이 포함돼 있어요.

  • import 블록: Lambda 함수에 필요한 라이브러리를 포함하는 블록이에요.
  • SDK 클라이언트와 로거의 전역 초기화: 핸들러 밖에 초기화 코드를 포함하면 실행 환경 재사용을 활용해 함수 성능을 개선해요. 자세한 내용은 Python Lambda 함수 코드 모범 사례를 참고하세요.
  • def upload_receipt_to_s3(bucket_name, key, receipt_content): 메인 lambda_handler 함수가 호출하는 도우미 함수예요.
  • def lambda_handler(event, context): 코드의 메인 핸들러 함수 로, 주요 애플리케이션 로직을 담고 있어요. Lambda가 함수 핸들러를 호출하면 Lambda 런타임이 함수에 두 인자를 전달해요. 함수가 처리할 데이터를 담은 이벤트 객체와 함수 호출에 대한 정보를 담은 컨텍스트 객체예요.

핸들러 이름 규칙 (Handler naming conventions)

Lambda 함수를 만들 때 정의하는 함수 핸들러 이름은 다음에서 파생돼요.

  • Lambda 핸들러 함수가 있는 파일의 이름
  • Python 핸들러 함수의 이름

위 예제에서 파일 이름이 lambda_function.py 라면 핸들러는 lambda_function.lambda_handler 로 지정돼요. 이것은 Lambda 콘솔로 만든 함수에 부여되는 기본 핸들러 이름이에요.

콘솔에서 다른 파일 이름이나 함수 핸들러 이름으로 함수를 만들면 기본 핸들러 이름을 편집해야 해요.

함수 핸들러 이름 변경(콘솔)

  1. Lambda 콘솔의 Functions 페이지를 열고 함수를 선택해요.
  2. Code 탭을 선택해요.
  3. Runtime settings 창까지 스크롤하고 Edit 를 선택해요.
  4. Handler 에 함수 핸들러의 새 이름을 입력해요.
  5. Save 를 선택해요.

Lambda 이벤트 객체 사용 (Using the Lambda event object)

Lambda가 함수를 호출하면 함수 핸들러에 이벤트 객체 인자를 전달해요. JSON 객체는 Lambda 함수에서 가장 일반적인 이벤트 형식이에요. 이전 섹션의 코드 예제에서 함수는 다음 형식의 입력을 기대해요.

{
    "Order_id": "12345",
    "Amount": 199.99,
    "Item": "Wireless Headphones"
}

함수가 다른 AWS 서비스에 의해 호출되면 입력 이벤트도 JSON 객체예요. 이벤트 객체의 정확한 형식은 함수를 호출하는 서비스에 따라 달라져요. 특정 서비스에 대한 이벤트 형식을 보려면 다른 AWS 서비스의 이벤트로 Lambda 호출 챕터에서 해당 페이지를 참고하세요.

입력 이벤트가 JSON 객체 형태라면 Lambda 런타임은 객체를 Python 딕셔너리로 변환해요. 입력 JSON의 값을 코드의 변수에 할당하려면 예제 코드에서처럼 표준 Python 딕셔너리 메서드를 사용해요.

함수에 데이터를 JSON 배열이나 다른 유효한 JSON 데이터 타입으로도 전달할 수 있어요. 다음 표는 Python 런타임이 이러한 JSON 타입을 변환하는 방식을 정의해요.

JSON 데이터 타입 Python 데이터 타입
object dictionary (dict)
array list (list)
number integer (int) 또는 floating point number (float)
string string (str)
Boolean Boolean (bool)
null NoneType (NoneType)

Lambda 컨텍스트 객체 접근 및 사용 (Accessing and using the Lambda context object)

Lambda 컨텍스트 객체는 함수 호출과 실행 환경에 대한 정보를 담고 있어요. Lambda는 함수가 호출될 때 컨텍스트 객체를 함수에 자동으로 전달해요. 컨텍스트 객체를 사용해 모니터링 목적으로 함수 호출에 대한 정보를 출력할 수 있어요.

컨텍스트 객체는 Lambda runtime interface client에 정의된 Python 클래스예요. 컨텍스트 객체 속성 중 하나의 값을 반환하려면 컨텍스트 객체에서 해당 메서드를 사용해요. 예를 들어 다음 코드 조각은 aws_request_id 속성(호출 요청의 식별자)의 값을 request 라는 변수에 할당해요.

request = context.aws_request_id

Lambda 컨텍스트 객체 사용과 사용 가능한 메서드·속성의 전체 목록에 대한 자세한 내용은 Lambda 컨텍스트 객체를 사용해 Python 함수 정보 검색을 참고하세요.

Python 핸들러의 유효한 핸들러 시그니처 (Valid handler signatures for Python handlers)

Python에서 핸들러 함수를 정의할 때 함수는 두 개의 인자를 받아야 해요. 첫 번째 인자는 Lambda 이벤트 객체이고 두 번째 인자는 Lambda 컨텍스트 객체예요. 관례적으로 이 입력 인자의 이름은 보통 event 와 context 지만 원하는 대로 이름을 지을 수 있어요. 핸들러 함수를 단일 입력 인자로 선언하면 Lambda가 함수 실행을 시도할 때 오류를 발생시켜요. Python에서 핸들러 함수를 선언하는 가장 일반적인 방법은 다음과 같아요.

def lambda_handler(event, context):

다음 예제처럼 함수 선언에 Python 타입 힌트를 사용할 수도 있어요.

from typing import Dict, Any

def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:

다른 AWS 서비스에서 생성된 이벤트와 컨텍스트 객체에 특정 AWS 타이핑을 사용하려면 aws-lambda-typing 패키지를 함수의 배포 패키지에 추가해요. 개발 환경에서 pip install aws-lambda-typing 을 실행해 이 라이브러리를 설치할 수 있어요. 다음 코드 조각은 AWS 특정 타입 힌트를 사용하는 방법을 보여줘요. 이 예제에서 기대되는 이벤트는 Amazon S3 이벤트예요.

from aws_lambda_typing.events import S3Event
from aws_lambda_typing.context import Context
from typing import Dict, Any

def lambda_handler(event: S3Event, context: Context) -> Dict[str, Any]:

핸들러 함수에 Python async 함수 타입은 사용할 수 없어요.

값 반환 (Returning a value)

선택적으로 핸들러는 JSON 직렬화 가능한 값을 반환할 수 있어요. 일반적인 반환 타입에는 dict, list, str, int, float, bool 이 있어요.

반환된 값에 일어나는 일은 호출 유형과 함수를 호출한 서비스에 따라 달라져요. 예를 들어:

  • RequestResponse 호출 유형을 사용해 Lambda 함수를 동기식으로 호출하면 Lambda는 Python 함수 호출의 결과를 Lambda 함수를 호출하는 클라이언트에 반환해요(호출 요청에 대한 HTTP 응답에서 JSON으로 직렬화). 예를 들어 AWS Lambda 콘솔은 RequestResponse 호출 유형을 사용하므로 콘솔에서 함수를 호출하면 콘솔이 반환된 값을 표시해요.
  • 핸들러가 json.dumps 로 직렬화할 수 없는 객체를 반환하면 런타임은 오류를 반환해요. 핸들러가 bytes 객체를 반환하는 경우는 예외예요.
  • 핸들러가 bytes 객체를 반환하면 런타임은 JSON 직렬화 없이 원시 이진 데이터로 그대로 전달하며 application/unknown 콘텐츠 유형을 사용해요.
  • 핸들러가 None 을 반환하면(return 문이 없는 Python 함수가 암시적으로 그렇게 함) 런타임은 null 을 반환해요.
  • Event 호출 유형(비동기식 호출)을 사용하면 값은 버려져요.

예제 코드에서 핸들러는 다음 Python 딕셔너리를 반환해요.

{
  "statusCode": 200,
  "message": "Receipt processed successfully"
}

Lambda 런타임은 이 딕셔너리를 직렬화해 함수를 호출한 클라이언트에 JSON 문자열로 반환해요.

참고

Python 3.9 이상 릴리스에서 Lambda는 오류 응답에 호출의 requestId를 포함해요.

핸들러에서 AWS SDK for Python(Boto3) 사용 (Using the AWS SDK for Python (Boto3) in your handler)

자주 Lambda 함수를 사용해 다른 AWS 서비스와 리소스와 상호작용하게 돼요. 이러한 리소스와 인터페이스하는 가장 간단한 방법은 AWS SDK for Python(Boto3)을 사용하는 것이에요. 지원되는 모든 Lambda Python 런타임에는 SDK for Python(Boto3) 버전이 포함돼 있어요.

그러나 코드가 SDK를 사용해야 한다면 함수의 배포 패키지에 SDK를 포함할 것을 강력히 권장해요. 배포 패키지에 SDK를 포함하면 종속성을 완전히 제어할 수 있고 다른 라이브러리와의 버전 불일치 문제 위험을 줄일 수 있어요. 자세한 내용은 Python의 런타임 종속성과 이전 버전 호환성을 참고하세요.

Lambda 함수에서 SDK for Python(Boto3)을 사용하려면 함수 코드 시작 부분의 import 블록에 다음 문을 추가해요.

import boto3

boto3 라이브러리를 함수의 배포 패키지에 추가하려면 pip install 명령을 사용해요. .zip 배포 패키지에 종속성을 추가하는 방법에 대한 자세한 지침은 종속성이 있는 .zip 배포 패키지 생성을 참고하세요. 컨테이너 이미지로 배포된 Lambda 함수에 종속성 추가에 대해 자세히 알아보려면 기본 이미지에서 이미지 생성 또는 대체 기본 이미지에서 이미지 생성을 참고하세요.

코드에서 boto3 를 사용할 때 클라이언트를 초기화하기 위해 자격 증명을 제공할 필요는 없어요. 예를 들어 예제 코드에서 다음 코드 줄을 사용해 Amazon S3 클라이언트를 초기화해요.

# Initialize the S3 client outside of the handler
s3_client = boto3.client('s3')

Python을 사용하면 Lambda가 자격 증명이 있는 환경 변수를 자동으로 생성해요. boto3 SDK는 초기화 중 함수의 환경 변수에서 이러한 자격 증명을 확인해요.

환경 변수 접근 (Accessing environment variables)

핸들러 코드에서 os.environ.get 메서드를 사용해 환경 변수를 참조할 수 있어요. 예제 코드에서는 다음 코드 줄을 사용해 정의된 RECEIPT_BUCKET 환경 변수를 참조해요.

# Access environment variables
bucket_name = os.environ.get('RECEIPT_BUCKET')

코드 시작 부분의 import 블록에 import os 문을 포함하는 것을 잊지 마세요.

Python Lambda 함수 코드 모범 사례 (Code best practices for Python Lambda functions)

Lambda 함수를 구축할 때 다음 목록의 지침을 준수해 최상의 코딩 방식을 사용하세요.

  • Lambda 핸들러를 핵심 로직과 분리하세요. 이렇게 하면 더 단위 테스트하기 쉬운 함수를 만들 수 있어요. 예를 들어 Python에서는 다음과 같이 보일 수 있어요.
    def lambda_handler(event, context):
        foo = event['foo']
        bar = event['bar']
        result = my_lambda_function(foo, bar)
    
    def my_lambda_function(foo, bar):
        // MyLambdaFunction logic here
    
  • 함수 배포 패키지의 종속성을 제어하세요. AWS Lambda 실행 환경에는 많은 라이브러리가 포함돼 있어요. Node.js와 Python 런타임의 경우 여기에는 AWS SDK가 포함돼요. 최신 기능과 보안 업데이트를 활성화하기 위해 Lambda는 이러한 라이브러리를 주기적으로 업데이트해요. 이 업데이트는 Lambda 함수의 동작에 미묘한 변화를 일으킬 수 있어요. 함수가 사용하는 종속성을 완전히 제어하려면 모든 종속성을 배포 패키지와 함께 패키징하세요.
  • 종속성의 복잡성을 최소화하세요. 실행 환경 시작 시 빠르게 로드되는 더 간단한 프레임워크를 선호하세요.
  • 배포 패키지 크기를 런타임 요구 사항으로 최소화하세요. 이렇게 하면 호출 전에 배포 패키지를 다운로드하고 압축을 푸는 데 걸리는 시간이 줄어들어요.
  • 실행 환경 재사용을 활용해 함수 성능을 개선하세요. SDK 클라이언트와 데이터베이스 연결을 함수 핸들러 밖에서 초기화하고, 정적 자산은 /tmp 디렉터리에 로컬로 캐시하세요. 함수의 같은 인스턴스가 처리하는 후속 호출은 이러한 리소스를 재사용할 수 있어요. 이렇게 하면 함수 실행 시간을 줄여 비용을 절약할 수 있어요. 호출 간 잠재적인 데이터 누출을 피하려면 실행 환경을 사용해 사용자 데이터, 이벤트, 보안 영향을 주는 기타 정보를 저장하지 마세요. 함수가 핸들러 내 메모리에 저장할 수 없는 변경 가능한 상태에 의존한다면 각 사용자에 대해 별도의 함수 또는 함수 버전을 만드는 것을 고려하세요.
  • 지속 연결을 유지하려면 keep-alive 지시문을 사용하세요. Lambda는 시간이 지나면 유휴 연결을 정리해요. 함수를 호출할 때 유휴 연결을 재사용하려고 하면 연결 오류가 발생해요. 지속 연결을 유지하려면 런타임과 연결된 keep-alive 지시문을 사용해요. 예제는 Node.js에서 keep-alive로 연결 재사용을 참고하세요.
  • 환경 변수를 사용해 운영 매개 변수를 함수에 전달하세요. 예를 들어 Amazon S3 버킷에 쓰는 경우 쓸 버킷 이름을 하드코딩하는 대신 버킷 이름을 환경 변수로 구성해요.
  • Lambda 함수에서 재귀적 호출을 피하세요. 함수가 자신을 호출하거나 함수를 다시 호출할 수 있는 프로세스를 시작하는 경우를 말해요. 이로 인해 의도하지 않은 함수 호출 양과 비용 상승이 발생할 수 있어요. 의도하지 않은 호출 양이 보이면 코드를 업데이트하는 동안 함수 예약 동시성을 즉시 0 으로 설정해 함수에 대한 모든 호출을 제한하세요.
  • Lambda 함수 코드에서 문서화되지 않은, 공개되지 않은 API를 사용하지 마세요. AWS Lambda 관리 런타임의 경우 Lambda는 Lambda 내부 API에 보안 및 기능 업데이트를 주기적으로 적용해요. 이러한 내부 API 업데이트는 이전 버전과 호환되지 않을 수 있어요. 함수가 이러한 비공개 API에 의존하면 호출 오류와 같은 의도하지 않은 결과가 발생할 수 있어요. 공개적으로 사용 가능한 API 목록은 API 참조를 참고하세요.
  • 멱등성 코드를 작성하세요. 함수에 멱등성 코드를 작성하면 중복 이벤트가 동일한 방식으로 처리되도록 보장해요. 코드는 이벤트를 올바르게 검증하고 중복 이벤트를 우아하게 처리해야 해요. 자세한 내용은 Lambda 함수를 멱등성으로 만드는 방법을 참고하세요.

더 알아보기 (Learn more)