DevOps/🐝 AWS

[AWS/Lambda] AWS Lambda 중복 trigger

키깡 2024. 5. 8.
728x90

slack bot을 만드는 과정에서 AWS Lambda를 사용하였는데, 어떻게 해도 duplicate function invocation을 방지하기가 어려웠다.
 
우선 공식문서(https://repost.aws/knowledge-center/lambda-function-duplicate-invocations)에서 하라는 대로 따라가 보기로 했다.
 

1️⃣ 재시도 횟수 0

구성 - 비동기식 호출 - 재시도 횟수를 0으로 만드는 것이다.
오류 발생 시 재시도를 하는 횟수를 0으로 맞추면, 확실히 3번 4번 trigger 되던 것은 방지된다.

 

2️⃣ dynamo db에 event ID 넣기

client side에서 할 수 있는 행위인데, 그냥 클라이언트 사이드에서 보내는 event ID를 dynamo DB에 저장하고 검증하기로 했다.
 
이후에 정리해서 클래스로 만든 것이긴 하지만, 이런식으로 db및 테이블을 만들고, slack 에서 보내는 event ID 값을 아래와 같이 저장한 후, check 하는 로직을 만들었다.

import boto3
from botocore.exceptions import ClientError

class DynamoDBManager:
    def __init__(self, region_name='ap-northeast-2'):
        self.dynamodb = boto3.resource('dynamodb', region_name=region_name)
        self.table_name = 'SlackEvents'

    def check_event(self, event_ts):
        table = self.dynamodb.Table(self.table_name)
        try:
            response = table.get_item(Key={'event_ts': event_ts})
            return 'Item' in response
        except ClientError as e:
            logger = setup_logger()
            logger.error(f"Error accessing DynamoDB: {e}")
            raise e

    def store_event(self, event_ts):
        table = self.dynamodb.Table(self.table_name)
        try:
            table.put_item(Item={'event_ts': event_ts})
        except ClientError as e:
            logger = setup_logger()
            logger.error(f"Error storing event in DynamoDB: {e}")
            raise e

    def create_table_if_not_exists(self):
        client = boto3.client('dynamodb', region_name=self.region_name)
        try:
            client.describe_table(TableName=self.table_name)
        except client.exceptions.ResourceNotFoundException:
            # 테이블 생성
            client.create_table(
                TableName=self.table_name,
                KeySchema=[{'AttributeName': 'event_ts', 'KeyType': 'HASH'}],
                AttributeDefinitions=[{'AttributeName': 'event_ts', 'AttributeType': 'S'}],
                ProvisionedThroughput={'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5}
            )
            logger = setup_logger()
            logger.info(f"Table {self.table_name} created successfully.")
            client.get_waiter('table_exists').wait(TableName=self.table_name)

 
다만 너무 복잡하다고 생각은 하여, 더 좋은 방법이 있다면 추후에 포스팅 할 예정이다.

댓글