SQS 이벤트에서 트리거된 AWS Lambda의 오류 처리
24897 단어 sqsserverlessawslambda
이 글은 처음에 발표되었다 my blog
에서 SQS 이벤트를 통해 Lambda 함수를 트리거하는 새로운 기능을 설명합니다.
이 기능을 사용하면 Lambda 함수에서 SQS 메시지를 삭제할 필요가 없습니다. AWS가 이 작업을 수행하지만 Lambda가 성공적으로 끝났을 때만 이 기능을 사용할 수 있습니다.
만약 Lambda가 실패하면 메시지는 대기열에 유지되고'가시성 시간 초과'후에 Lambda 기능을 다시 볼 수 있습니다. 이 시간은 Amazon SQS가 다른 소비자들이 메시지를 수신하고 처리하는 것을 막는 시간입니다. (기본값은 30초)
SQS 대기열
VisibilityTimeout
속성 생성 시 또는 특정 메시지(사용ChangeMessageVisibility call에서 이 시간 초과를 구성할 수 있습니다.이러한 상황을 처리하지 않으면 다음과 같은 상황이 발생할 수 있습니다. Lambda가 한동안 실행되고 메시지가 실패할 때, AWS의 계산 능력과 느슨한 자금을 낭비하고, SQS 대기열은 공중에 떠 있는 미처리 메시지에 따라 증가합니다.
마지막으로, 모든 메시지는 만료 시간 후에 SQS 대기열에서 삭제됩니다 (속성
MessageRetentionPeriod
. SQS 대기열을 만들 때 이 속성을 지정할 수 있습니다. 기본값은 4일). 그러나 발생해서는 안 됩니다.너는 반드시 스스로 국면을 통제해야 한다.우리는 어떻게 그것을 통제합니까?
나는 적어도 두 가지 가능성을 생각했다.다른 것을 알고 있다면 댓글로 공유해 주세요.
고정 큐 또는 DLQ
DLQ는 실패한 메시지를 저장하는 데 사용되는 대기열의 이름입니다.기술적으로 SQS 대기열과 다를 바 없습니다.이것은 단지 대기열에 대한 용도일 뿐이다.메시지가 Lambda 함수에서 올바르게 처리되지 않을 때 DLQ로 전달하고 DLQ에서 단독 함수로 처리할 수 있습니다. 예를 들어 주 Lambda 함수로 다시 보내거나 관리자에게 알림을 보내거나 삭제만 할 수 있습니다.
여기에서 DLQ를 사용하는 응용 프로그램의 예를 보여 드리겠습니다.
이렇게 간단했으면 좋겠습니다. - 서버 없는 문서에 따라 Lambda 함수에만
onError
속성을 지정해야 합니다. 아래와 같습니다.functions:
receiver:
handler: receiver.handler
events:
- sqs:
arn:
Fn::GetAtt:
- MyQueue
- Arn
onError: arn:aws:sqs:us-east-1:811338114639:ReceiverDLQ
여기서 ARN을 기존 SQS 대기열에 지정합니다.불행하게도 현재는 실패하고 오류가 발생했습니다.
onError currently only supports SNS topic arns due to a race condition when using SQS queue arns and updating the IAM role. Please check the docs for more info.
the doc에서도 이 점을 언급했다.다행히도
onError
속성을 사용하지 않고 오래된 좋은 CloudFormation 스타일로 설정하는 해결 방법이 있습니다.먼저 배포 중에 서버가 없는 SQS 대기열을 만들려면
resources
섹션의 serverless.yaml
에서 새 SQS 대기열을 정의해야 합니다.resources:
Resources:
ReceiverDeadLetterQueue:
Type: "AWS::SQS::Queue"
Properties:
QueueName: "receiverDLQ"
MessageRetentionPeriod: 1209600 # 14 days in seconds
그리고 오류 처리 설정을 추가해야 합니다.여기에는 두 가지 선택이 있습니다.DeadLetterConfig
.여기서, 나는 두 번째 옵션을 설명할 것이다. 그것은 잘 작동하고 있다.
먼저 새 응용 프로그램 스택을 만들 때 생성할 리소스를 정의합니다.
resources:
Resources:
MyQueue:
Type: "AWS::SQS::Queue"
Properties:
QueueName: "MyQueue"
VisibilityTimeout: 30
MessageRetentionPeriod: 60
RedrivePolicy:
deadLetterTargetArn:
"Fn::GetAtt":
- ReceiverDeadLetterQueue
- Arn
maxReceiveCount: 1
ReceiverDeadLetterQueue:
Type: "AWS::SQS::Queue"
Properties:
QueueName: "receiverDLQ"
MessageRetentionPeriod: 1209600 # 14 days in seconds
우리는 두 개의 대기열을 정의했다. RedrivePolicy
와 MyQueue
, 그리고 원본 대기열ReceiverDeadLetterQueue
에 재구동 정책을 설정했다.이렇게 하면 메시지가 원본 대기열에 의해
MyQueue
회 이상 수신되면 maxReceiveCount
로 리디렉션됩니다.중요한 것은 AWS 콘솔에서
ReceiverDeadLetterQueue
의 메시지를 보려면'메시지 수신'으로 간주되기 때문에 람다 함수는 뷰어 화면을 닫은 후 DLQ로 직접 전송되기 때문에 얻을 기회가 없다는 것을 명심하는 것입니다.이제 AWS에 애플리케이션 스택을 배치할 때 테스트를 수행할 수 있습니다.
소스 코드는 브랜치
MyQueue
에서 찾을 수 있습니다here.먼저
redrive-policy
에 JSON 메시지를 제출하고 로그를 확인하여 함수가 예상대로 작동하는지 테스트할 수 있습니다.export QUEUE_URL=`aws sqs get-queue-url --queue-name MyQueue --query 'QueueUrl' --output text --profile=sls`
aws sqs send-message --queue-url ${QUEUE_URL} --message-body "{ \"text\" : \"test2\"}" --profile=sls
sls logs -f receiver -t
다음과 같이 기록해야 합니다.2018-07-19 20:40:19.789 (+02:00) b0a7c784-eeea-5901-8786-944e33b92c18 event: {"Records":[{"messageId":"3a0a90f5-8fb5-4cbb-8b46-017039272637","receiptHandle":"AQEBfT4rwo5KGoqL1RGBVp4WlsSumH5ToYEENfhDGPXUv2RPdLNDsUTJ/3QjeevDqK5YPrQ1xoSixvACIYlMD7HtXNh0iRRS8VBqutR7tx8ZMkucagRweZ3WyYxXImrVcsD33NIPFlUeldQjRTTnPKfjo+BCZ5TZCs1ndnSKVrqwMzMi7MwTDtI4a1b0IxEJdhiWot7eJ7EwaPmdfVpgK6K/vUQeW+jep3M1cUhNGwoz7H/2bL2FVX54uzfjoShLY7JymmkAuPzqQ/3KQPPvOyMvuragXmzE8VxA+phHHl66hWBj0nlOSWwYbXAFI765/Ik6zPk+nwKm2PoQs3hvPl1aDzAU1FHtqYqaH6GmJ7AAaHwNnufv83ez2hoZGv2AhhDE","body":"{ \"text\" : \"test2\"}","attributes":{"ApproximateReceiveCount":"1","SentTimestamp":"1532025619465","SenderId":"AIDAJLGFXMWT34E5GOTAS","ApproximateFirstReceiveTimestamp":"1532025619496"},"messageAttributes":{},"md5OfBody":"9be3787fa6959a8ed52b3fd5be1aa95a","eventSource":"aws:sqs","eventSourceARN":"arn:aws:sqs:us-east-1:811338114639:MyQueue","awsRegion":"us-east-1"}]}
2018-07-19 20:40:19.790 (+02:00) b0a7c784-eeea-5901-8786-944e33b92c18 text: test2
그리고 오류가 있는 JSON 본문을 보내서 Lambda에서 오류를 일으킵니다. 예를 들어aws sqs send-message --queue-url ${QUEUE_URL} --message-body "test" --profile=sls
애플리케이션 로그 보기:sls logs -f receiver -t
너는 이런 잘못을 보게 될 것이다.SyntaxError: Unexpected token e in JSON at position 1
at Object.parse (native)
at exports.handler (/var/task/receiver.js:15:29)
Lambda가 성공하지 못했기 때문에 메시지는 MyQueue
로 되돌아갔지만, 두 번째입니다. (첫 번째는 당신이 그것을 보낼 때) DLQ로 다시 지정해야 합니다.DLQ에 메시지를 표시하고 새 메시지가 표시되는 것을 볼 수 있습니다.
export DLQ_QUEUE_URL=`aws sqs get-queue-url --queue-name receiverDLQ --query 'QueueUrl' --output text --profile=sls`
aws sqs receive-message --queue-url ${DLQ_QUEUE_URL} --visibility-timeout 0 --profile=sls
참고: MyQueue
을 0으로 설정하면 명령을 실행할 때마다 같은 메시지를 조회할 수 있으며 메시지가 다시 보일 때까지 기다릴 필요가 없습니다.이제 DLQ의 실패 메시지에 대해 원하는 작업을 수행할 수 있습니다. 예를 들어 DLQ를 처리하고 다시 시도하여 주 응용 프로그램 대기열로 보낼지 삭제할지 결정할 수 있습니다.
Lambda 함수의 오류 처리
DLQ를 설정하지 않고 오류를 처리하기를 원한다고 생각해 보십시오.
함수는 어떻게 보입니까?
다음은 예입니다.
// receiverErrorHandling.js
'use strict';
var AWS = require('aws-sdk');
var sqs = new AWS.SQS({
region: 'us-east-1'
});
exports.handler = (event, context, callback) => {
const NUM_OF_RETRIES = 3;
try {
console.log('event: ', JSON.stringify(event));
throw new Error("simulated error");
// this will never be reached in our demo
callback(null, "How did you get here??");
} catch (e) {
console.log('Handled error', e);
// we will send new message with incremented count, if below retry limit, otherwise exit with status code 200
// to allow AWS to remove SQS message, but return status message.
var message = JSON.parse(event.Records[0].body); // message boody arrives as string JSON
var retried = message.retryCount | 0; // we've set batchSize=1 in sls config so it's save to get by index.
if (retried > NUM_OF_RETRIES-1) {
const response = "Failed after retries";
console.log(response);
callback(null, response);
} else {
retried++;
message.retryCount = retried;
// send a new message which is a copy of received message but with incremender retry counter.
var accountId = context.invokedFunctionArn.split(":")[4];
var queueUrl = 'https://sqs.us-east-1.amazonaws.com/' + accountId + '/MyQueue';
var params = {
MessageBody: JSON.stringify(message),
QueueUrl: queueUrl,
DelaySeconds: 10
};
sqs.sendMessage(params, function (err, data) {
if (err) {
console.log(err);
callback( "Failed to retry after error" );
} else {
const response = "Failed, but will retry " + retried + " time";
console.log(response);
callback(null,response);
}
});
}
}
};
이 함수는 다음과 같은 주요 오류를 처리합니다.--visibility-timeout
블록에 던져지고 잡히면 외부에서 전파하는 것을 허락하지 않습니다. 그렇지 않으면 메시지는 대기열에 남아 다시 Lambda에 도착합니다.MyQueue
속성을 설정했습니다.E, g. 만약 try
블록에 있다면, 우리는 일부 외부 서비스에 연결될 것이며, 이로 인해 오류가 발생할 것이다. 우리는 지연 시간이 지나면 그들이 스스로 복구하고 다시 시도할 것이라고 예상한다.catch
에서 60초로 정의할 것입니다.resources:
Resources:
MyQueue:
Type: "AWS::SQS::Queue"
Properties:
QueueName: "MyQueue"
VisibilityTimeout: 30 # 30 sec.
MessageRetentionPeriod: 60 # 60 sec.
메시지는 JSON을 보내더라도 해당 메시지를 대상으로 해석해야 하는 텍스트 형식입니다. var message = JSON.parse(event.Records[0].body);
또한 Lambda는 여러 SQS 메시지를 동시에 처리할 수 있습니다. 첫 번째 메시지는 다음과 같습니다.event.Records[0]
다른 상황에서는 안전하지 않을 수 있지만, Lambda는 다음과 같이 구성의 단일 메시지 DelaySeconds
만 폴링합니다. receiver:
handler: receiverErrorHandling.handler
events:
- sqs:
arn:
Fn::GetAtt:
- MyQueue
- Arn
- batchSize: 1
Github에서 코드를 가져와 자신을 테스트할 수 있습니다.JSON 메시지를 보낼 수 있습니다.
curl <sender url> -d '{"text" : "Hello"}'
및 로그 보기:sls logs -f receiver -t
다음 로그 시퀀스가 표시됩니다.START RequestId: 72ddf8e2-a835-5d10-9088-ab37291615f8 Version: $LATEST
2018-07-27 22:22:10.532 (+02:00) 72ddf8e2-a835-5d10-9088-ab37291615f8 event: {"Records":[{"messageId":"5d6caf38-23ff-4408-bba0-85b538fad092","receiptHandle":"AQEBV5+zoh9qYCqoKGye8D4gYjpXp1cXTUzm2gNLyAvpEV3XBRsDtyPn81C0G4LaMm3urF6yOUi8or6Zg29V+c7MjRq1nvw4XBk9rGEADdkVqd4/YGo2eGdfbuSOoPVQUbfN2Qk36VG/rjHmQHAYNTudfC4dD6upMfLHNsQEvaiUCUViF7ONa7H0ZGqcvEqNSfv6wH992PpRsRHkgJ52KhqVGVkn2wGUzO7djUv4zMfWWtD7ZGI0N6DB15OpeTtZTYtW8qbzcINuj51/B3Ty5oKh864sidQddm4VuqQQkOEOKVu4n+j/fAW+yOX20RfxJno+mCoh04gD7eEvGI/XgpAKAYsInKEpC8Meu6rjl9Icy2GFUp14e3Za1M8u9VlzsOZV","body":"{\"text\" : \"Hello\"}","attributes":{"ApproximateReceiveCount":"1","SentTimestamp":"1532722929910","SenderId":"AROAJ77G56ARJABY7JWOY:sqs-triggers-error-handling-dev-sender","ApproximateFirstReceiveTimestamp":"1532722929911"},"messageAttributes":{},"md5OfBody":"35efbdc1c909ad760d1b85d56e450139","eventSource":"aws:sqs","eventSourceARN":"arn:aws:sqs:us-east-1:811338114639:MyQueue","awsRegion":"us-east-1"}]}
2018-07-27 22:22:10.532 (+02:00) 72ddf8e2-a835-5d10-9088-ab37291615f8 Handled error Error: simulated error
at exports.handler.e (/var/task/receiverErrorHandling.js:17:9)
2018-07-27 22:22:10.702 (+02:00) 72ddf8e2-a835-5d10-9088-ab37291615f8 Failed, but will retry 1 time
END RequestId: 72ddf8e2-a835-5d10-9088-ab37291615f8
REPORT RequestId: 72ddf8e2-a835-5d10-9088-ab37291615f8 Duration: 174.19 ms Billed Duration: 200 ms Memory Size: 1024 MB Max Memory Used: 34 MB
...
2018-07-27 22:22:20.768 (+02:00) 08200246-1f91-5f43-983f-51939ea57388 Failed, but will retry 2 time
...
2018-07-27 22:22:30.830 (+02:00) 4313584b-9c88-5da8-a5ac-0b9e1db69a3a Failed, but will retry 3 time
...
2018-07-27 22:22:40.876 (+02:00) 7c1ab10d-66ab-58d1-ac12-e2d8e7ed3f43 Failed after retries
...
로그에서 10초마다 다시 시도하는 시간 스탬프를 볼 수 있습니다.이것이 바로 우리가 SQS에 보내는 메시지에 설정try
을 통해 실현하고자 하는 것이다.배달:
참고 문헌:
Reference
이 문제에 관하여(SQS 이벤트에서 트리거된 AWS Lambda의 오류 처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/piczmar_0/error-handling-in-aws-lambda-trigger-by-sqs-events-3amp텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)