배달 못한 편지 대기열로 실패한 작업 격리

AWSBeginner
지금 연습하기

소개

잘못된 주문 작업은 작업자가 처리할 때마다 실패합니다. 시도 횟수를 제한하고 조사를 위해 별도의 대기열에 보관하며 정상 주문은 여전히 완료되는지 확인합니다.

표시 제한 시간과 재전달 처리와 해당 실습의 선행 안내 실습을 먼저 완료하세요. 이 독립적인 VM에는 작업자와 빈 주문 테이블이 제공됩니다. 대기열, 메시지와 소비자 연결은 직접 구성합니다.

인증 시험 관련 주제

이 실습은 다음 시험 주제에 대한 실습 경험을 제공합니다.

소스 대기열을 배달 못한 편지 대기열에 연결

이 단계에서는 빈 표준 대기열 두 개를 만들고 소스 대기열에 횟수가 제한된 리드라이브를 설정합니다.

**배달 못한 편지 대기열 (dead letter queue, DLQ)**은 소스 대기열의 수신 한도를 초과한 작업을 보관합니다. Terminal 옆에서 AWS View를 사용하여 두 대기열, 실제 시도와 저장된 주문을 비교하세요. 참조 데이터를 유지하세요.

cd /home/labex/project

실패한 작업의 대상을 만들고 대기열 주소를 저장하세요.

DEAD_URL=$(aws sqs create-queue --queue-name labex-q03-dead --query QueueUrl --output text)

리드라이브 정책은 대기열 URL이 아닌 서비스 리소스 식별자인 대상의 ARN을 참조합니다. 해당 ARN을 선택하세요.

DEAD_ARN=$(aws sqs get-queue-attributes --queue-url "$DEAD_URL" --attribute-names QueueArn --query Attributes.QueueArn --output text)

작은 JSON 정책을 작성하세요. 셸은 $DEAD_ARN에 대상 ARN을 넣습니다. maxReceiveCount는 두 번의 전달 시도를 허용하고 그 이후의 수신이 메시지를 DLQ로 이동시킵니다.

cat > redrive-policy.json <<EOF
{
  "deadLetterTargetArn": "$DEAD_ARN",
  "maxReceiveCount": 2
}
EOF

SQS 대기열 속성은 리드라이브 정책을 다른 JSON 문서 안의 JSON 문자열로 표현합니다. --rawfile은 정책 파일을 해당 문자열로 읽고 >는 속성 파일을 씁니다.

jq -n --rawfile policy redrive-policy.json '{VisibilityTimeout:"30",RedrivePolicy:$policy}' > queue-attributes.json

이 속성으로 소스 대기열을 만드세요.

QUEUE_URL=$(aws sqs create-queue --queue-name labex-q03-jobs --attributes file://queue-attributes.json --query QueueUrl --output text)
aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names QueueArn VisibilityTimeout RedrivePolicy

표시 제한 시간은 30, 정책 대상은 labex-q03-dead, 수신 한도는 2여야 합니다. 소비자 연결에 사용할 소스 ARN을 저장하세요.

QUEUE_ARN=$(aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names QueueArn --query Attributes.QueueArn --output text)

AWS View에는 빈 대기열 두 개가 표시되고 작업자 실행이나 주문은 없습니다. 리드라이브 정책 자체가 메시지를 처리하지는 않습니다. 소비자를 통해 수신해야 합니다.

소비자 연결 및 정상 처리 증명

이 단계에서는 Lambda 이벤트 소스 매핑을 연결하고 유효한 작업의 실제 처리를 검증합니다.

대기열에서 작업자로 연결되는 매핑

매핑은 대기열을 폴링하고 작업자를 호출합니다. 처리에 성공하면 메시지를 확인 처리할 수 있습니다.

이벤트 소스 매핑은 소스 대기열을 Lambda 소비자에 연결합니다. 메시지를 폴링하고 SQS Records 이벤트로 전달하며 성공적으로 처리된 메시지를 삭제합니다. 제공된 실행 역할에는 소스 대기열의 수신/삭제 권한, 주문 테이블 쓰기와 로깅 권한만 있습니다. 작업자는 1–10 범위 밖의 수량을 거부합니다. 코드와 권한은 준비물입니다. 직접 수행할 작업은 대기열 연결과 실패 격리입니다.

각 시도에서 작업 하나를 확인할 수 있도록 배치 크기가 1인 매핑을 만드세요.

MAPPING_ID=$(aws lambda create-event-source-mapping --function-name labex-q03-worker --event-source-arn "$QUEUE_ARN" --batch-size 1 --enabled --query UUID --output text)

연결을 읽으세요.

aws lambda get-event-source-mapping --uuid "$MAPPING_ID" --query '{Source:EventSourceArn,Function:FunctionArn,Batch:BatchSize,State:State}'

labex-q03-jobs의 소스 ARN, 함수 labex-q03-worker, 배치 크기 1과 상태 Enabled가 나와야 합니다. 매핑 존재 여부는 설정의 증거입니다. 실제 저장된 주문이 처리를 증명합니다.

정상 작업을 전송하세요.

aws sqs send-message --queue-url "$QUEUE_URL" --message-body '{"id":"good-order","quantity":2}'

작업자가 결과를 반환하고 주문 테이블에 good-order가 표시될 때까지 AWS View를 관찰하세요. 처리는 비동기입니다. 메시지를 직접 수신하지 말고 소비자에게 잠시 시간을 주세요. 다음으로 주문을 읽으세요.

aws dynamodb get-item --table-name labex-q03-orders --key '{"id":{"S":"good-order"}}' --consistent-read --query Item

수량 2와 합계 600이 나와야 합니다. 두 대기열을 확인하세요.

aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible
aws sqs get-queue-attributes --queue-url "$DEAD_URL" --attribute-names ApproximateNumberOfMessages

두 대기열은 모두 비어 있어야 합니다. 작업자가 비즈니스 쓰기를 완료했고 소비자가 성공한 작업을 확인 처리했습니다. 정상 메시지는 DLQ에 들어갈 대상이 아닙니다.

제한된 재시도와 실패 격리 관찰

이 단계에서는 잘못된 작업을 전송하고 네이티브 리드라이브가 이를 DLQ에 넣기 전에 실제 처리 실패 시도를 관찰합니다.

제한된 실패에서 DLQ로 이동

이 실습의 수신 한도는 2이므로 이후 수신은 작업자를 세 번째 호출하는 대신 실패한 작업을 DLQ로 이동시킵니다.

**포이즌 메시지 (poison message)**는 데이터나 처리 로직 때문에 반복적으로 실패합니다. 테스트용 잘못된 수량 0을 전송하세요.

aws sqs send-message --queue-url "$QUEUE_URL" --message-body '{"id":"poison-order","quantity":0}'

AWS View에는 작업자의 실패한 시도가 표시됩니다. 메시지는 표시 제한 시간이 만료될 때까지 처리 중 상태로 남으며 이후 소비자가 다시 수신할 수 있습니다. DLQ에 사용 가능한 작업 하나가 생길 때까지 시도와 대기열 개수를 관찰하세요. 30초의 제한 시간과 두 번의 시도를 사용하므로 대략 1분에 처리 시간을 더한 만큼 기다리세요. 소비자가 실행 중인 동안 작업을 직접 수신하거나 삭제하지 마세요. 그러면 수신 횟수와 실험이 달라집니다.

두 실패 시도는 같은 메시지 ID와 수신 횟수 1, 2를 갖습니다. poison-order에 대한 저장된 주문은 나타나지 않습니다. 수신 한도에 도달한 후 다음 네이티브 수신은 함수를 세 번째 호출하는 대신 메시지를 소스 대기열 밖으로 이동시킵니다.

CLI로 대기열 상태를 확인하세요.

aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible
aws sqs get-queue-attributes --queue-url "$DEAD_URL" --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible

소스의 사용 가능한 작업과 처리 중인 작업은 모두 0이고 DLQ에는 사용 가능한 작업 하나가 있어야 합니다. AWS View는 원래 본문을 표시합니다. 잘못된 수량과 실패에 대한 실제 작업자 로그를 확인하세요.

aws logs filter-log-events --log-group-name /aws/lambda/labex-q03-worker --query 'events[].message'

모든 주문 항목을 읽으세요.

aws dynamodb scan --table-name labex-q03-orders --query Items

good-order/2/600만 남습니다. 메시지를 버리거나 잘못된 주문을 쓰지 않고 실패를 격리했습니다. DLQ로 이동하는 것은 복구나 비즈니스 성공이 아닙니다. 작업 복구와 중복 제거는 이후 단원과 프로젝트 챌린지에서 다룹니다.

두 번의 수신 실패 후 포이즌 작업은 DLQ에 남고 정상 주문만 저장된 AWS View 예시

연결과 소유한 리소스 제거

이 단계에서는 대기열과 결과를 삭제하기 전에 소비자 연결을 중지합니다.

이벤트 소스 매핑을 먼저 제거하세요.

aws lambda delete-event-source-mapping --uuid "$MAPPING_ID" --query UUID --output text

일회용 대기열 두 개를 삭제하세요. DLQ에 보관된 테스트용 포이즌 작업도 함께 버려집니다.

aws sqs delete-queue --queue-url "$QUEUE_URL"
aws sqs delete-queue --queue-url "$DEAD_URL"

정상 주문과 이 실습의 실행 로그를 제거하세요.

aws dynamodb delete-item --table-name labex-q03-orders --key '{"id":{"S":"good-order"}}'
aws logs delete-log-group --log-group-name /aws/lambda/labex-q03-worker

성공한 API 응답으로 리소스가 없고 참조 리소스가 유지되는지 확인하세요.

aws lambda list-event-source-mappings --function-name labex-q03-worker --query EventSourceMappings
aws sqs list-queues
aws dynamodb scan --table-name labex-q03-orders --query Items
aws dynamodb scan --table-name labex-q03-reference --query Items

매핑과 주문 목록은 비어 있고 대기열 URL은 남아 있지 않으며 참조 항목에는 여전히 keep unchanged가 있습니다. 제공된 작업자와 테이블 구조는 남습니다. AWS View는 같은 리소스 상태를 보여 줍니다. 인증 실패나 네트워크 실패는 삭제를 증명할 수 없습니다.

일반 로컬 정책 파일을 제거하세요.

rm -f redrive-policy.json queue-attributes.json

환경을 종료하기 전에 정리 검사를 실행하세요.

요약

수신 한도가 제한된 SQS 소스 대기열을 DLQ에 연결하고 Lambda 소비자를 연결하여 정상 주문의 저장을 검증했습니다. 잘못된 작업이 두 번 실패한 후 비즈니스 쓰기 없이 DLQ로 이동하는 것을 관찰하고 제공된 리소스를 유지하면서 본인의 매핑, 대기열, 결과와 로그를 제거했습니다.