튜토리얼: Lambda와 Amazon SQS 사용하기

튜토리얼: Lambda와 Amazon SQS 사용하기

이 튜토리얼에서는 Amazon Simple Queue Service(Amazon SQS) 큐에서 메시지를 소비하는 Lambda 함수를 만들어요. Lambda 함수는 큐에 새 메시지가 추가될 때마다 실행돼요. 함수는 메시지를 Amazon CloudWatch Logs 스트림에 써요. 다음 다이어그램은 튜토리얼을 완료하는 데 사용하는 AWS 리소스를 보여줘요.

이 튜토리얼을 완료하려면 다음 단계를 수행해요:

  1. 메시지를 CloudWatch Logs에 쓰는 Lambda 함수를 만듭니다.

  2. Amazon SQS 큐를 만듭니다.

  3. Lambda 이벤트 소스 매핑을 만듭니다. 이벤트 소스 매핑은 Amazon SQS 큐를 읽고 새 메시지가 추가되면 Lambda 함수를 호출합니다.

  4. 큐에 메시지를 추가하고 CloudWatch Logs에서 결과를 모니터링해서 설정을 테스트합니다.

출처: AWS Lambda 개발자 안내서

본문

사전 요구 사항

AWS Command Line Interface 설치

AWS Command Line Interface를 아직 설치하지 않았다면 최신 버전의 AWS CLI 설치 또는 업데이트의 단계를 따라 설치하세요.

튜토리얼에는 명령을 실행할 명령줄 터미널 또는 셸이 필요해요. Linux와 macOS에서는 선호하는 셸과 패키지 관리자를 사용하세요.

참고 Windows에서는 Lambda에서 일반적으로 사용하는 일부 Bash CLI 명령(예: zip)이 운영 체제의 기본 제공 터미널에서 지원되지 않아요. Windows 통합 버전의 Ubuntu와 Bash를 사용하려면 Windows Subsystem for Linux를 설치하세요.

실행 역할 만들기

실행 역할은 Lambda 함수에 AWS 서비스와 리소스에 액세스할 권한을 부여하는 AWS Identity and Access Management(IAM) 역할이에요. 함수가 Amazon SQS에서 항목을 읽도록 허용하려면 AWSLambdaSQSQueueExecutionRole 권한 정책을 연결하세요.

실행 역할을 만들고 Amazon SQS 권한 정책을 연결하려면

  1. IAM 콘솔의 역할 페이지를 엽니다.

  2. 역할 만들기(Create role)를 선택합니다.

  3. 신뢰할 수 있는 엔터티 유형(Trusted entity type)에서 AWS 서비스(AWS service)를 선택합니다.

  4. 사용 사례(Use case)에서 Lambda를 선택합니다.

  5. 다음(Next)을 선택합니다.

  6. 권한 정책(Permissions policies) 검색 상자에 AWSLambdaSQSQueueExecutionRole을 입력합니다.

  7. AWSLambdaSQSQueueExecutionRole 정책을 선택한 다음 다음(Next)을 선택합니다.

  8. 역할 세부 정보(Role details)의 역할 이름(Role name)에 lambda-sqs-role을 입력한 다음 역할 만들기(Create role)를 선택합니다.

역할 생성 후 실행 역할의 Amazon 리소스 이름(ARN)을 기록해 두세요. 나중에 필요해요.

함수 만들기

Amazon SQS 메시지를 처리하는 Lambda 함수를 만들어요. 함수 코드는 Amazon SQS 메시지의 본문을 CloudWatch Logs에 기록해요.

이 튜토리얼은 Node.js 24 런타임을 사용하지만 다른 런타임 언어로도 예시 코드를 제공했어요. 관심 있는 런타임에 대한 코드를 보려면 다음 상자의 탭을 선택하세요. 이 단계에서 사용할 JavaScript 코드는 JavaScript 탭의 첫 번째 예시에 있어요.

.NET

SDK for .NET GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. .NET을 사용해서 SQS 이벤트를 Lambda로 소비해요.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
using Amazon.Lambda.Core;
using Amazon.Lambda.SQSEvents;


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace SqsIntegrationSampleCode
{
    public async Task FunctionHandler(SQSEvent evnt, ILambdaContext context)
    {
        foreach (var message in evnt.Records)
        {
            await ProcessMessageAsync(message, context);
        }

        context.Logger.LogInformation("done");
    }

    private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context)
    {
        try
        {
            context.Logger.LogInformation($"Processed message {message.Body}");

            // TODO: Do interesting work based on the new message
            await Task.CompletedTask;
        }
        catch (Exception e)
        {
            //You can use Dead Letter Queue to handle failures. By configuring a Lambda DLQ.
            context.Logger.LogError($"An error occurred");
            throw;
        }

    }
}

Go

SDK for Go V2 GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. Go를 사용해서 SQS 이벤트를 Lambda로 소비해요.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration_sqs_to_lambda

import (
	"fmt"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(event events.SQSEvent) error {
	for _, record := range event.Records {
		err := processMessage(record)
		if err != nil {
			return err
		}
	}
	fmt.Println("done")
	return nil
}

func processMessage(record events.SQSMessage) error {
	fmt.Printf("Processed message %s\n", record.Body)
	// TODO: Do interesting work based on the new message
	return nil
}

func main() {
	lambda.Start(handler)
}

Java

SDK for Java 2.x GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. Java를 사용해서 SQS 이벤트를 Lambda로 소비해요.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;

public class Function implements RequestHandler<SQSEvent, Void> {
    @Override
    public Void handleRequest(SQSEvent sqsEvent, Context context) {
        for (SQSMessage msg : sqsEvent.getRecords()) {
            processMessage(msg, context);
        }
        context.getLogger().log("done");
        return null;
    }

    private void processMessage(SQSMessage msg, Context context) {
        try {
            context.getLogger().log("Processed message " + msg.getBody());

            // TODO: Do interesting work based on the new message

        } catch (Exception e) {
            context.getLogger().log("An error occurred");
            throw e;
        }

    }
}

JavaScript

SDK for JavaScript (v3) GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. JavaScript를 사용해서 SQS 이벤트를 Lambda로 소비해요.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const message of event.Records) {
    await processMessageAsync(message);
  }
  console.info("done");
};

async function processMessageAsync(message) {
  try {
    console.log(`Processed message ${message.body}`);
    // TODO: Do interesting work based on the new message
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}

TypeScript를 사용해서 SQS 이벤트를 Lambda로 소비해요.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { SQSEvent, Context, SQSHandler, SQSRecord } from "aws-lambda";

export const functionHandler: SQSHandler = async (
  event: SQSEvent,
  context: Context
): Promise<void> => {
  for (const message of event.Records) {
    await processMessageAsync(message);
  }
  console.info("done");
};

async function processMessageAsync(message: SQSRecord): Promise<any> {
  try {
    console.log(`Processed message ${message.body}`);
    // TODO: Do interesting work based on the new message
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}

PHP

SDK for PHP GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. PHP를 사용해서 SQS 이벤트를 Lambda로 소비해요.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\InvalidLambdaEvent;
use Bref\Event\Sqs\SqsEvent;
use Bref\Event\Sqs\SqsHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler extends SqsHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws InvalidLambdaEvent
     */
    public function handleSqs(SqsEvent $event, Context $context): void
    {
        foreach ($event->getRecords() as $record) {
            $body = $record->getBody();
            // TODO: Do interesting work based on the new message
        }
    }
}

$logger = new StderrLogger();
return new Handler($logger);

Python

SDK for Python (Boto3) GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. Python을 사용해서 SQS 이벤트를 Lambda로 소비해요.

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event, context):
    for message in event['Records']:
        process_message(message)
    print("done")

def process_message(message):
    try:
        print(f"Processed message {message['body']}")
        # TODO: Do interesting work based on the new message
    except Exception as err:
        print("An error occurred")
        raise err

Ruby

SDK for Ruby GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. Ruby를 사용해서 SQS 이벤트를 Lambda로 소비해요.

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event:, context:)
  event['Records'].each do |message|
    process_message(message)
  end
  puts "done"
end

def process_message(message)
  begin
    puts "Processed message #{message['body']}"
    # TODO: Do interesting work based on the new message
  rescue StandardError => err
    puts "An error occurred"
    raise err
  end
end

Rust

SDK for Rust GitHub에 더 많은 내용이 있어요. 전체 예시와 설정·실행 방법은 Serverless examples 저장소에서 확인하세요. Rust를 사용해서 SQS 이벤트를 Lambda로 소비해요.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::event::sqs::SqsEvent;
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

async fn function_handler(event: LambdaEvent<SqsEvent>) -> Result<(), Error> {
    event.payload.records.iter().for_each(|record| {
        // process the record
        tracing::info!("Message body: {}", record.body.as_deref().unwrap_or_default())
    });

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}

Node.js Lambda 함수를 만들려면

  1. 프로젝트용 디렉터리를 만든 다음 해당 디렉터리로 전환합니다.

    mkdir sqs-tutorial
    cd sqs-tutorial
    
  2. 샘플 JavaScript 코드를 index.js라는 새 파일에 복사합니다.

  3. 다음 zip 명령을 사용해서 배포 패키지를 만듭니다.

    zip function.zip index.js
    
  4. create-function AWS CLI 명령을 사용해서 Lambda 함수를 만듭니다. role 매개변수에는 앞서 만든 실행 역할의 ARN을 입력합니다. 참고 Lambda 함수와 Amazon SQS 큐는 동일한 AWS 리전에 있어야 해요.

    aws lambda create-function --function-name ProcessSQSRecord \
    --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
    --role arn:aws:iam::{{111122223333}}:role/lambda-sqs-role
    

함수 테스트

invoke AWS CLI 명령과 샘플 Amazon SQS 이벤트를 사용해서 Lambda 함수를 수동으로 호출해요.

샘플 이벤트로 Lambda 함수를 호출하려면

  1. 다음 JSON을 input.json이라는 파일로 저장합니다. 이 JSON은 Amazon SQS가 Lambda 함수로 보낼 수 있는 이벤트를 시뮬레이션하며, "body"에는 큐의 실제 메시지가 포함됩니다. 이 예시에서 메시지는 "test"예요. 예시 Amazon SQS 이벤트

    이것은 테스트 이벤트예요—메시지나 계정 번호를 변경할 필요는 없어요.

    {
        "Records": [
            {
                "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
                "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
                "body": "test",
                "attributes": {
                    "ApproximateReceiveCount": "1",
                    "SentTimestamp": "1545082649183",
                    "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                    "ApproximateFirstReceiveTimestamp": "1545082649185"
                },
                "messageAttributes": {},
                "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
                "eventSource": "aws:sqs",
                "eventSourceARN": "arn:aws:sqs:us-east-1:111122223333:my-queue",
                "awsRegion": "us-east-1"
            }
        ]
    }
    
  2. 다음 invoke AWS CLI 명령을 실행합니다. 이 명령은 응답에 CloudWatch 로그를 반환해요. 로그 검색에 대한 자세한 내용은 AWS CLI로 로그 액세스를 참고하세요.

    aws lambda invoke --function-name ProcessSQSRecord --payload file://input.json out --log-type Tail \
    --query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode
    

    cli-binary-format 옵션은 AWS CLI 버전 2를 사용하는 경우 필요해요. 기본 설정으로 만들려면 aws configure set cli-binary-format raw-in-base64-out을 실행하세요. 자세한 내용은 *AWS Command Line Interface 사용 설명서(버전 2)*의 AWS CLI 지원 전역 명령줄 옵션을 참고하세요.

  3. 응답에서 INFO 로그를 찾습니다. 여기가 Lambda 함수가 메시지 본문을 기록하는 곳입니다. 다음과 같은 로그가 보일 거예요:

    2023-09-11T22:45:04.271Z	348529ce-2211-4222-9099-59d07d837b60	INFO	Processed message test
    2023-09-11T22:45:04.288Z	348529ce-2211-4222-9099-59d07d837b60	INFO	done
    

Amazon SQS 큐 만들기

Lambda 함수가 이벤트 소스로 사용할 수 있는 Amazon SQS 큐를 만들어요. Lambda 함수와 Amazon SQS 큐는 동일한 AWS 리전에 있어야 해요.

큐를 만들려면

  1. Amazon SQS 콘솔을 엽니다.

  2. 큐 만들기(Create queue)를 선택합니다.

  3. 큐 이름을 입력합니다. 다른 모든 옵션은 기본 설정으로 둡니다.

  4. 큐 만들기(Create queue)를 선택합니다.

큐를 만든 후 큐의 ARN을 기록해 두세요. 다음 단계에서 큐를 Lambda 함수와 연결할 때 필요해요.

이벤트 소스 구성

이벤트 소스 매핑을 만들어서 Amazon SQS 큐를 Lambda 함수에 연결하세요. 이벤트 소스 매핑은 Amazon SQS 큐를 읽고 새 메시지가 추가되면 Lambda 함수를 호출해요.

Amazon SQS 큐와 Lambda 함수 간의 매핑을 만들려면 create-event-source-mapping AWS CLI 명령을 사용하세요. 예시:

aws lambda create-event-source-mapping --function-name ProcessSQSRecord  --batch-size 10 \
--event-source-arn arn:aws:sqs:{{us-east-1:111122223333:my-queue}}

이벤트 소스 매핑 목록을 보려면 list-event-source-mappings 명령을 사용하세요. 예시:

aws lambda list-event-source-mappings --function-name ProcessSQSRecord

테스트 메시지 보내기

Lambda 함수에 Amazon SQS 메시지를 보내려면

  1. Amazon SQS 콘솔을 엽니다.

  2. 앞서 만든 큐를 선택합니다.

  3. 메시지 보내기 및 받기(Send and receive messages)를 선택합니다.

  4. 메시지 본문(Message body)에 "this is a test message." 같은 테스트 메시지를 입력합니다.

  5. 메시지 보내기(Send message)를 선택합니다.

Lambda는 큐에서 업데이트를 폴링해요. 새 메시지가 있으면 Lambda는 큐의 이 새 이벤트 데이터로 함수를 호출해요. 함수 핸들러가 예외 없이 반환되면 Lambda는 메시지가 성공적으로 처리된 것으로 간주하고 큐에서 새 메시지 읽기를 시작해요. 메시지를 성공적으로 처리한 후 Lambda는 자동으로 큐에서 메시지를 삭제해요. 핸들러가 예외를 던지면 Lambda는 메시지 배치가 성공적으로 처리되지 않은 것으로 간주하고 동일한 메시지 배치로 함수를 호출해요.

CloudWatch 로그 확인

함수가 메시지를 처리했는지 확인하려면

  1. Lambda 콘솔의 함수 페이지를 엽니다.

  2. ProcessSQSRecord 함수를 선택합니다.

  3. 모니터링(Monitor)을 선택합니다.

  4. CloudWatch 로그 보기(View CloudWatch logs)를 선택합니다.

  5. CloudWatch 콘솔에서 함수의 로그 스트림(Log stream)을 선택합니다.

  6. INFO 로그를 찾습니다. 여기가 Lambda 함수가 메시지 본문을 기록하는 곳입니다. Amazon SQS 큐에서 보낸 메시지가 보일 거예요. 예시:

    2023-09-11T22:49:12.730Z b0c41e9c-0556-5a8b-af83-43e59efeec71 INFO Processed message this is a test message.
    

리소스 정리

튜토리얼용으로 만든 리소스를 유지하지 않으려면 이제 삭제할 수 있어요. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 비용이 부과되는 것을 방지할 수 있어요.

실행 역할을 삭제하려면

  1. IAM 콘솔의 역할 페이지를 엽니다.

  2. 만든 실행 역할을 선택합니다.

  3. 삭제(Delete)를 선택합니다.

  4. 텍스트 입력 필드에 역할 이름을 입력하고 삭제(Delete)를 선택합니다.

Lambda 함수를 삭제하려면

  1. Lambda 콘솔의 함수 페이지를 엽니다.

  2. 만든 함수를 선택합니다.

  3. 작업(Actions), 삭제(Delete)를 선택합니다.

  4. 텍스트 입력 필드에 confirm을 입력하고 삭제(Delete)를 선택합니다.

Amazon SQS 큐를 삭제하려면

  1. AWS Management Console에 로그인하고 https://console.aws.amazon.com/sqs/에서 Amazon SQS 콘솔을 엽니다.

  2. 만든 큐를 선택합니다.

  3. 삭제(Delete)를 선택합니다.

  4. 텍스트 입력 필드에 confirm을 입력합니다.

  5. 삭제(Delete)를 선택합니다.

더 알아보기 (Learn more)

이 튜토리얼은 Amazon SQS를 Lambda 함수와 사용하는 방법을 설명해요. Amazon SQS 통합에 대한 자세한 내용은 Lambda 개발자 안내서의 Amazon SQS와 함께 Lambda 사용을 참고하세요.