Lambda 재귀 루프 감지 EventBridge 지원, 도쿄와 서울 리전에서 직접 확인해 보기
Lambda와 EventBridge로 이벤트 기반 구조를 만들다 보면, 함수가 처리 결과를 이벤트로 다시 발행하는 경우를 경험해 보신 적이 있으신가요?이때 규칙 패턴을 넓게 잡거나 이벤트 버스 이름을 잘못 넣으면, 함수가 자신을 호출한 버스에 다시 이벤트를 보내 무한 루프가 생기는 상황이 생길 수 있습니다.호출이 계속 이어지면서 동시성과 비용이 순식간에 올라가고, 대부분 청구서나 경보를 보고 나서야 알게 됩니다. 안녕하세요. GS Neotek 송상민 입니다.이런 상황에 활용하기 좋은 기능이 나와서 직접 실험해 보았습니다. AWS 발표 소개 2026년 10월 14일, AWS Lambda의 재귀 루프 감지 기능이 Amazon EventBridge 커스텀 이벤트 버스까지 지원하도록 확장되었습니다.Lambda 함수가 자신을 호출한 이벤트 버스로 다시 이벤트를 보내는 실수를 하면, Lambda가 이 루프를 감지해서 끊어 준다는 내용입니다.도쿄와 서울 리전에서 실제로 무한 루프를 만들어 확인해 보았고, 서울 리전 사용자라면 알아 두어야 할 결과가 나와서 정리했습니다. 재귀 루프 감지는 어떻게 동작하나요 공식 문서에 따르면 동작 방식은 다음과 같습니다. 지원 서비스가 Lambda로 보내는 이벤트에는 X-Ray 추적 헤더 기반의 메타데이터가 붙고, 함수가 지원 SDK로 다시 이벤트를 쓰면 이 메타데이터의 호출 횟수가 올라갑니다. 같은 이벤트에서 시작된 호출 체인이 약 16회에 이르면 Lambda가 다음 호출을 중단합니다. 중단되면 RecursiveInvocationsDropped CloudWatch 지표가 기록되고, AWS Health Dashboard와 운영 담당자 이메일로 알림이 갑니다(최대 3.5시간 지연). 별도 설정이 필요 없는 기본 기능이며, 의도적으로 재귀를 쓰는 함수만 PutFunctionRecursionConfig로 끌 수 있습니다. 먼저 알아야 할 것: 커스텀 이벤트 버스가 두 종류가 되었습니다 이번 발표를 이해하려면 한 달 전 소식을 먼저 알아야 합니다.2026년 9월 24일 EventBridge가 커스텀 이벤트 버스를 새로 출시하면서, 기존 버스는 “Custom event bus – classic”으로 이름이 바뀌었습니다.그리고 이번 재귀 루프 감지의 대상은 이 중 새 커스텀 이벤트 버스입니다. 두 버스의 가장 큰 차이는 버스가 이벤트를 저장하느냐입니다. 기존 버스(default 버스 포함)는 이벤트를 저장하지 않습니다.들어오는 순간 규칙(Rule)이 패턴을 보고 타깃(Target)으로 바로 밀어 주고 끝납니다. 새 버스는 이벤트를 일정 기간(기본 24시간, 최대 1년) 쌓아 둡니다.구독자(Subscriber)가 각자 거기서 꺼내 가는 구조라서, 과거 시점부터 다시 받기, 배치로 받기, 순서대로 받기 같은 설정을 구독자마다 할 수 있습니다. 규칙 하나에 타깃을 여러 개 다는 것과 구독자를 여러 개 만드는 것은 결과가 같으므로, 대상 수가 핵심 차이는 아닙니다. 구분기존 버스(classic, default)새 커스텀 이벤트 버스이벤트 전달규칙 + 타깃(들어오는 즉시 전달)구독자(Subscriber)(보관된 이벤트를 꺼내 감)이벤트 보관없음기본 24시간, 최대 1년배치·순서 보장1건씩, 순서 보장 없음1. 배치 크기 설정2. FIFO 순서 보장·중복 제거APIeventseventsv2(SDK에서는 eventbridgev2)출시 리전모든 상용 리전14개 리전(서울 미포함)이번 재귀 루프 감지대상 아님대상 실험 한눈에 보기 항목내용실험 일자2026-10-29 ~ 2026-10-30공통 조건1. Python 3.13 런타임2. 재귀 루프 감지 설정 Terminate(기본값)3. 함수 코드에 30회 안전장치도쿄(ap-northeast-1)새 커스텀 이벤트 버스 + 구독자 → 16회 호출 후 Lambda가 중단(2회 반복 동일)서울(ap-northeast-2)1. 기존 커스텀 이벤트 버스 + 규칙 → 31회 호출, Lambda가 중단하지 않음(3회 반복 동일)2. 같은 함수의 SQS 루프 → 16회 호출 후 중단3. 새 커스텀 이벤트 버스 → 서울 리전에 아직 없음 실험 1: 도쿄 리전, 새 커스텀 이벤트 버스 새 버스와 구독자를 만들고, 구독자의 대상으로 Lambda 함수를 연결했습니다(비동기 호출, 1건씩 전달).함수에는 일부러 “자신을 호출한 버스에 다시 이벤트를 보내는” 버그를 넣었고, 감지가 동작하지 않을 때를 대비해 30회에서 스스로 멈추는 안전장치를 코드에 두었습니다. 새 버스는 API가 따로 있어서, 함수에서도 eventbridgev2 클라이언트를 써야 합니다.Python 3.13 런타임에 기본으로 들어 있는 boto3에는 이 클라이언트가 없어서, 최신 boto3(1.43.122)를 Lambda 계층(Layer)으로 넣었습니다. import json, os import boto3 eb = boto3.client("eventbridgev2") # 새 커스텀 이벤트 버스 전용 클라이언트 BUS_ARN = os.environ["BUS_ARN"] MAX_HOPS = int(os.environ["SAFETY_MAX_HOPS"]) # 30: 감지가 안 될 때를 위한 안전장치 def handler(event, context): detail = event.get("detail", {}) hop = int(detail.get("hop", 0)) run = detail.get("run", "manual") tid = os.environ.get("_X_AMZN_TRACE_ID", "") lineage = [p for p in tid.split(";") if p.startswith("Lineage=")] print(json.dumps({"run": run, "hop": hop, "lineage": lineage[0] if lineage else None})) if hop >= MAX_HOPS: print(json.dumps({"run": run, "hop": hop, "safety_stop": True})) return # 일부러 넣은 버그: 자신을 호출한 버스로 다시 이벤트를 보낸다 eb.put_events(EventBusArn=BUS_ARN, Entries=[{ "Source": "lab.recursion", "DetailType": "loop", "Detail": json.dumps({"run": run, "hop": hop + 1}), }]) 구독자는 아래처럼 만들었습니다.기존 방식의 “규칙 + 타깃”이 여기서는 구독자 하나에 필터와 대상, 전달 설정이 함께 들어갑니다. eb.create_subscriber( Name="recursion-v2-sub", EventBusArn=bus_arn, Type="UNORDERED", FilterConfiguration={"Filters": [{"Scope": "DATA", "Pattern":...
최신 댓글