Go에서 Lambda 함수 핸들러 정의 - AWS Lambda

Go에서 Lambda 함수 핸들러 정의

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

이 페이지에서는 프로젝트 설정, 이름 지정 규칙, 모범 사례를 포함하여 Go에서 Lambda 함수 핸들러를 사용하는 방법을 설명합니다. 이 페이지에는 주문에 대한 정보를 가져와서 텍스트 파일 영수증을 생성하고 해당 파일을 Amazon Simple Storage Service(S3) 버킷에 넣는 Go Lambda 함수의 예제도 포함되어 있습니다. 함수를 작성한 후 배포하는 방법에 대한 자세한 내용은 .zip 파일 아카이브를 사용하여 Go Lambda 함수 배포 또는 컨테이너 이미지로 Go Lambda 함수 배포 섹션을 참조하세요.

Go 핸들러 프로젝트 설정

Go에서 작성된 Lambda 함수는 Go 실행 파일로 작성됩니다. 다음 go mod init 명령을 사용하여 다른 Go 프로젝트를 초기화하는 것과 동일한 방식으로 Go Lambda 함수 프로젝트를 초기화할 수 있습니다.

go mod init example-go

여기에서 example-go는 모듈 이름입니다. 이를 다른 것으로 대체할 수 있습니다. 이 명령은 프로젝트를 초기화하고 프로젝트의 종속성을 나열하는 go.mod 파일을 생성합니다.

go get 명령을 사용하여 프로젝트에 외부 종속성을 추가합니다. 예를 들어 Go의 모든 Lambda 함수에 대해서는 Go용 Lambda 프로그래밍 모델을 구현하는 github.com/aws/aws-lambda-go/lambda 패키지를 포함해야 합니다. 다음 go get 명령을 사용하여 이 패키지를 포함합니다.

go get github.com/aws/aws-lambda-go

함수 코드는 Go 파일에 있어야 합니다. 다음 예제에서는 이 파일의 이름을 main.go로 지정합니다. 이 파일에서는 핸들러 메서드에 핵심 함수 논리와 이 핸들러를 호출하는 main() 함수를 구현합니다.

예제 Go Lambda 함수 코드

다음 예제 Go Lambda 함수 코드는 주문에 대한 정보를 입력으로 가져와서 텍스트 파일 영수증을 생성하고 해당 파일을 Amazon S3 버킷에 넣습니다.

main.go Lambda 함수
package main import ( "context" "encoding/json" "fmt" "log" "os" "strings" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" ) type Order struct { OrderID string `json:"order_id"` Amount float64 `json:"amount"` Item string `json:"item"` } var ( s3Client *s3.Client ) func init() { // Initialize the S3 client outside of the handler, during the init phase cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Fatalf("unable to load SDK config, %v", err) } s3Client = s3.NewFromConfig(cfg) } func uploadReceiptToS3(ctx context.Context, bucketName, key, receiptContent string) error { _, err := s3Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &bucketName, Key: &key, Body: strings.NewReader(receiptContent), }) if err != nil { log.Printf("Failed to upload receipt to S3: %v", err) return err } return nil } func handleRequest(ctx context.Context, event json.RawMessage) error { // Parse the input event var order Order if err := json.Unmarshal(event, &order); err != nil { log.Printf("Failed to unmarshal event: %v", err) return err } // Access environment variables bucketName := os.Getenv("RECEIPT_BUCKET") if bucketName == "" { log.Printf("RECEIPT_BUCKET environment variable is not set") return fmt.Errorf("missing required environment variable RECEIPT_BUCKET") } // Create the receipt content and key destination receiptContent := fmt.Sprintf("OrderID: %s\nAmount: $%.2f\nItem: %s", order.OrderID, order.Amount, order.Item) key := "receipts/" + order.OrderID + ".txt" // Upload the receipt to S3 using the helper method if err := uploadReceiptToS3(ctx, bucketName, key, receiptContent); err != nil { return err } log.Printf("Successfully processed order %s and stored receipt in S3 bucket %s", order.OrderID, bucketName) return nil } func main() { lambda.Start(handleRequest) }

main.go 파일은 다음 코드 섹션을 포함하고 있습니다.

  • package main: Go에서 func main() 함수를 포함하는 패키지의 이름은 항상 main이어야 합니다.

  • import 블록: 이 블록을 사용하여 Lambda 함수에 필요한 라이브러리를 포함합니다.

  • type Order struct {} 블록: 이 Go 구조체에서 예상 입력 이벤트의 형태를 정의합니다.

  • var () 블록: 이 블록을 사용하여 Lambda 함수에 사용할 전역 변수를 정의합니다.

  • func init() {}: 이 init() 메서드의 초기화 단계에서 Lambda가 실행하기를 원하는 모든 코드를 포함합니다.

  • func uploadReceiptToS3(...) {}: 기본 handleRequest 핸들러 메서드에서 참조하는 도우미 메서드입니다.

  • func handleRequest(ctx context.Context, event json.RawMessage) error {}: 기본 애플리케이션 논리를 포함한 기본 핸들러 메서드입니다.

  • func main() {}: Lambda 핸들러에 필요한 진입점입니다. lambda.Start() 메서드에 대한 인수는 기본 핸들러 메서드입니다.

이 함수가 제대로 작동하려면 실행 역할s3:PutObject 작업을 허용해야 합니다. 또한 RECEIPT_BUCKET 환경 변수를 정의해야 합니다. 성공적으로 호출되면 Amazon S3 버킷은 영수증 파일을 포함합니다.

핸들러 이름 지정 규칙

Go의 Lambda 함수의 경우에는 핸들러에 어떤 이름이라도 사용할 수 있습니다. 이 예제의 핸들러 메서드 이름은 handleRequest입니다. 코드에서 핸들러 값을 참조하려면 _HANDLER 환경 변수를 사용합니다.

.zip 배포 패키지를 사용하여 배포된 Go 함수의 경우 함수 코드가 포함된 실행 파일의 이름은 bootstrap이어야 합니다. 또한 bootstrap 파일은 .zip 파일의 루트에 있어야 합니다. 컨테이너 이미지를 사용하여 배포된 Go 함수의 경우 실행 파일에 어떤 이름이라도 사용할 수 있습니다.

입력 이벤트 객체 정의 및 액세스

JSON은 Lambda 함수의 가장 일반적인 표준 입력 형식입니다. 이 예제에서 함수는 다음과 유사한 입력을 예상합니다.

{ "order_id": "12345", "amount": 199.99, "item": "Wireless Headphones" }

Go에서 Lambda 함수로 작업할 때 예상되는 입력 이벤트의 형태를 Go 구조체로 정의할 수 있습니다. 이 예제에서는 Order를 나타내는 구조체를 정의합니다.

type Order struct { OrderID string `json:"order_id"` Amount float64 `json:"amount"` Item string `json:"item"` }

이 구조체는 예상 입력 형태와 일치합니다. 구조체를 정의한 후에는 encoding/json 표준 라이브러리와 호환되는 일반 JSON 유형을 받아들이는 핸들러 서명을 작성할 수 있습니다. 그런 다음 func Unmarshal 함수를 사용하여 이를 구조체로 역직렬화할 수 있습니다. 이는 핸들러의 처음 몇 줄에 설명되어 있습니다.

func handleRequest(ctx context.Context, event json.RawMessage) error { // Parse the input event var order Order if err := json.Unmarshal(event, &order); err != nil { log.Printf("Failed to unmarshal event: %v", err) return err ... }

역직렬화 후에는 order 변수의 필드에 액세스할 수 있습니다. 예를 들어 order.OrderID는 원래 입력에서 "order_id"의 값을 검색합니다.

참고

encoding/json 패키지는 내보낸 필드에만 액세스할 수 있습니다. 내보내기를 위해서는 이벤트 구문의 필드 이름이 대문자로 표시되어야 합니다.

Lambda 컨텍스트 객체 액세스 및 사용

Lambda 컨텍스트 객체에는 호출, 함수, 실행 환경에 관한 정보가 포함되어 있습니다. 이 예제에서는 핸들러 서명에서 이 변수를 ctx로 선언했습니다.

func handleRequest(ctx context.Context, event json.RawMessage) error { ... }

ctx context.Context 입력은 함수 핸들러의 선택적 인수입니다. 허용되는 핸들러 서명에 대한 자세한 내용은 Go 핸들러에 대해 유효한 핸들러 서명 섹션을 참조하세요.

AWS SDK를 사용하여 다른 서비스를 직접적으로 호출하는 경우 몇 가지 주요 영역에서 컨텍스트 객체가 필요합니다. 예를 들어 SDK 클라이언트를 올바르게 초기화하려면 다음과 같이 컨텍스트 객체를 사용하여 올바른 AWS SDK 구성을 로드할 수 있습니다.

// Load AWS SDK configuration using the default credential provider chain cfg, err := config.LoadDefaultConfig(ctx)

SDK 호출 자체에 컨텍스트 객체가 입력으로 필요할 수 있습니다. 예를 들어 s3Client.PutObject 호출은 컨텍스트 객체를 첫 번째 인수로 수락합니다.

// Upload the receipt to S3 _, err = s3Client.PutObject(ctx, &s3.PutObjectInput{ ... })

AWS SDK 요청 외에도 함수 모니터링에 컨텍스트 객체를 사용할 수 있습니다. 컨텍스트 객체에 대한 자세한 내용은 Lambda 컨텍스트 객체를 사용하여 Go 함수 정보 검색 섹션을 참조하세요.

Go 핸들러에 대해 유효한 핸들러 서명

Go에서 Lambda 함수 핸들러를 빌드할 때 몇 가지 옵션들이 있으며 다만 다음과 같은 규칙들을 반드시 준수해야 합니다.

  • 핸들러는 하나의 함수여야 합니다.

  • 핸들러는 0~2개의 인수를 취할 수 있습니다. 인수가 2개일 경우, 첫 번째 인수는 context.Context를 구현해야 합니다.

  • 핸들러는 0~2개의 인수를 반환할 수 있습니다. 반환 값이 1개일 경우, 이 값은 error를 구현해야 합니다. 반환 값이 2개일 경우, 두 번째 값은 error를 구현해야 합니다.

다음 목록은 유효한 핸들러 서명을 열거합니다. TInTOutencoding/json 표준 라이브러리와 호환 가능한 유형을 나타냅니다. 이러한 유형들이 역직렬화되는 방식에 관한 자세한 내용은 func Unmarshal을 참조하시기 바랍니다.

  • func ()
  • func () error
  • func () (TOut, error)
  • func (TIn) error
  • func (TIn) (TOut, error)
  • func (context.Context) error
  • func (context.Context) (TOut, error)
  • func (context.Context, TIn) error
  • func (context.Context, TIn) (TOut, error)

핸들러에서 AWS SDK for Go v2 사용

종종 Lambda 함수를 사용하여 다른 AWS 리소스와 상호 작용하거나 업데이트하는 경우가 있습니다. 이러한 리소스와 인터페이스로 접속하는 가장 간단한 방법은 AWS SDK for Go v2를 사용하는 것입니다.

참고

AWS SDK for Go(v1)는 유지 관리 모드이며 2025년 7월 31일에 지원이 종료됩니다. 앞으로는 AWS SDK for Go v2만 사용하는 것을 권장합니다.

함수에 SDK 종속성을 추가하려면 필요한 특정 SDK 클라이언트에 go get 명령을 사용하세요. 이전의 예제 코드에서는 config 라이브러리와 s3 라이브러리를 사용했습니다. go.modmain.go 파일이 포함된 디렉터리에서 다음 명령을 실행하여 이러한 종속성을 추가합니다.

go get github.com/aws/aws-sdk-go-v2/config go get github.com/aws/aws-sdk-go-v2/service/s3

그런 다음 함수의 가져오기 블록에서 그에 따른 종속성을 가져옵니다.

import ( ... "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" )

핸들러에서 SDK를 사용하는 경우에는 클라이언트를 올바른 설정으로 구성하세요. 가장 간단한 방법은 기본 자격 증명 제공업체 체인을 사용하는 것입니다. 이 예제에서는 이러한 구성을 로드하는 한 가지 방법을 보여줍니다.

// Load AWS SDK configuration using the default credential provider chain cfg, err := config.LoadDefaultConfig(ctx) if err != nil { log.Printf("Failed to load AWS SDK config: %v", err) return err }

이러한 구성을 cfg 변수에 로드한 후에 해당 변수를 클라이언트 인스턴스에 전달할 수 있습니다. 예제 코드는 다음과 같이 Amazon S3 클라이언트를 인스턴스화합니다.

// Create an S3 client s3Client := s3.NewFromConfig(cfg)

이 예제에서는 init() 함수를 호출할 때마다 초기화할 필요가 없도록 함수에서 Amazon S3 클라이언트를 초기화했습니다. 문제는 init() 함수에서 Lambda가 컨텍스트 객체에 액세스할 수 없다는 점입니다. 이 문제를 해결하려면 초기화 단계에서 context.TODO()와 같은 자리 표시자를 전달할 수 있습니다. 나중에 클라이언트를 사용하여 직접적으로 호출할 때 전체 컨텍스트 객체를 전달합니다. 이 해결 방법은 AWS SDK 클라이언트 초기화 및 호출에서 컨텍스트 사용에도 설명되어 있습니다.

SDK 클라이언트를 구성하고 초기화한 후에는 이를 사용하여 다른 AWS 서비스와 상호 작용할 수 있습니다. 예제 코드는 다음과 같이 Amazon S3 PutObject API를 직접적으로 호출합니다.

_, err = s3Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &bucketName, Key: &key, Body: strings.NewReader(receiptContent), })

환경 변수에 액세스

핸들러 코드에서 os.Getenv() 메서드를 사용하여 모든 환경 변수를 참조할 수 있습니다. 이 예제에서는 다음 코드 줄을 사용하여 정의된 RECEIPT_BUCKET 환경 변수를 참조합니다.

// Access environment variables bucketName := os.Getenv("RECEIPT_BUCKET") if bucketName == "" { log.Printf("RECEIPT_BUCKET environment variable is not set") return fmt.Errorf("missing required environment variable RECEIPT_BUCKET") }

전역 상태 사용

함수를 호출할 때마다 새 리소스가 생성되지 않도록 하려면 Lambda 함수의 핸들러 코드 외부에서 전역 변수를 선언하고 수정할 수 있습니다. var 블록 또는 문에서 이러한 전역 변수를 정의합니다. 또한 핸들러는 초기화 단계 동안 실행되는 init() 함수를 선언할 수 있습니다. init 메서드는 표준 Go 프로그램에서와 마찬가지로 AWS Lambda에서도 동일하게 동작합니다.

Go Lambda 함수의 코드 모범 사례

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

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

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

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

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

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

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

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

  • Lambda 함수에서 함수가 자기 자신을 간접적으로 호출하거나 함수를 다시 간접적으로 호출할 수 있는 프로세스를 시작하는 재귀적 호출을 사용하지 마세요. 리커시브 코드를 사용할 경우, 의도하지 않은 함수 호출이 증가하고 비용이 상승할 수 있습니다. 의도치 않게 간접 호출이 대량으로 발생하는 경우 함수의 예약된 동시성을 즉시 0으로 설정하여 코드를 업데이트하는 동안 해당 함수에 대한 모든 간접 호출을 제한합니다.

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

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