はじめに
業務でLambdaと組み合わせてSQSやSNSをよく使うのですが、イベントを正しくハンドリングする必要があります。
イベントの構造についてドキュメント等があるかもしれませんが、検証した方が早いと思い、自分で検証環境を作って確認してみました。
概要
以下によるイベントの構造をLambdaでログ出力して検証します。
- SQS
- SNS
- SNS + SQS
設定
Lambda
以下のLambdaを作成し、イベントをログ出力します。
exports.handler = async (event) => {
console.log(`event: ${JSON.stringify(event)}`);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
IAM
LambdaがSQSのメッセージを受け取れるようにするために、Lambda作成時に自動生成されたロールに対して、AmazonSQSFullAccessとAmazonSNSFullAccessを付与します。
SQS
SQSを標準設定で作成し、先ほど作成したLambdaをトリガーに設定します。
SNS
SNSを標準設定で作成し、以下をサブスクリプションとして指定します。
- 先ほど作成したSQS
- 先ほど作成したLambda
検証結果
SQSの場合
SQSのコンソール画面からテストメッセージを送信してみます。
イベント内容
body
のところに先ほど送ったメッセージTest message
が入るようです。
{
"Records": [
{
"messageId": "xxx",
"receiptHandle": "xxx",
"body": "Test message",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1653699635640",
"SenderId": "xxx",
"ApproximateFirstReceiveTimestamp": "1653699635650"
},
"messageAttributes": {},
"md5OfBody": "xxx",
"eventSource": "aws:sqs",
"eventSourceARN": "<arn_of_sqs>",
"awsRegion": "ap-northeast-1"
}
]
}
SNSの場合
以下のメッセージをSNSから送信
イベント内容
Subject: メッセージのタイトル
Message: メッセージの本文
MessageAttributes: メッセージ属性
{
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "<arn_of_sns>",
"Sns": {
"Type": "Notification",
"MessageId": "xxx",
"TopicArn": "<arn_of_sns>",
"Subject": "Test message from SNS - Title",
"Message": "Test message from SNS - Raw message ",
"Timestamp": "2022-05-28T01:13:53.904Z",
"SignatureVersion": "1",
"Signature": "xxx",
"SigningCertUrl": "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-xxx.pem",
"UnsubscribeUrl": "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=<EventSubscriptionArn>",
"MessageAttributes": {
"key1": {
"Type": "String",
"Value": "\"Value1\""
},
"Key2": {
"Type": "String",
"Value": "[\"Value2\", \"Value3\"]"
}
}
}
}
]
}
SNS + SQSの場合
同様に、SNSから同じメッセージを送ります。
イベント内容
body
の中にSNSのイベントが入るようです。SQSを経由するからっぽいですね。
{
"Records": [
{
"messageId": "xxx",
"receiptHandle": "xxx",
"body": "{\n \"Type\" : \"Notification\",\n \"MessageId\" : \"xxx\",\n \"TopicArn\" : \"<arn_of_sqs>\",\n \"Subject\" : \"Test message from SNS - Title\",\n \"Message\" : \"Test message from SNS - Raw message\",\n \"Timestamp\" : \"2022-05-28T01:26:45.690Z\",\n \"SignatureVersion\" : \"1\",\n \"Signature\" : \"xxx\",\n \"SigningCertURL\" : \"https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-xxx.pem\",\n \"UnsubscribeURL\" : \"https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=<arn_of_sqs>\",\n \"MessageAttributes\" : {\n \"key1\" : {\"Type\":\"String\",\"Value\":\"\\\"Value1\\\"\"},\n \"key2\" : {\"Type\":\"String.Array\",\"Value\":\"[\\\"Value2\\\", \\\"Value3\\\"]\"}\n }\n}",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1653701205731",
"SenderId": "xxx",
"ApproximateFirstReceiveTimestamp": "1653701205742"
},
"messageAttributes": {},
"md5OfBody": "xxx",
"eventSource": "aws:sqs",
"eventSourceARN": "<arn_of_sqs>",
"awsRegion": "ap-northeast-1"
}
]
}
bodyの中を整形してみると、以下のようになり、SNSから直接Lambdaにメッセージを送った時と同様になりました。
{
"Type": "Notification",
"MessageId": "xxx",
"TopicArn": "<arn_of_sqs>",
"Subject": "Test message from SNS - Title",
"Message": "Test message from SNS - Raw message",
"Timestamp": "2022-05-28T01:26:45.69Z",
"SignatureVersion": "1",
"Signature": "xxx",
"SigningCertURL": "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-xxx.pem",
"UnsubscribeURL": "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=<arn_of_sqs>",
"MessageAttributes": {
"key1": {
"Type": "String",
"Value": "\"Value1\""
},
"key2": {
"Type": "String.Array",
"Value": "[\"Value2\", \"Value3\"]"
}
}
}
まとめ
結論、以下それぞれでイベントの構造が異なることが分かりました。
- SQS
- SNS
- SNS + SQS
これらを用いて開発する際はイベントの構造に注意するとよさそうです。