我有一个 SNS 主题,我向其发布 SNS 消息。我订阅了一个 SQS 队列,这又会触发 Lambda 函数。
根据此文档页面,我应该收到与此类似的通知:
{
"Type": "Notification",
"MessageId": "63a3f6b6-d533-4a47-aef9-fcf5cf758c76",
"TopicArn": "arn:aws:sns:us-west-2:123456789012:MyTopic",
"Subject": "Testing publish to subscribed queues",
"Message": "Hello world!",
"Timestamp": "2012-03-29T05:12:16.901Z",
"SignatureVersion": "1",
"Signature": "EXAMPLEnTrFPa3...",
"SigningCertURL": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-f3ecfb7224c7233fe7bb5f59f96de52f.pem",
"UnsubscribeURL": "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:123456789012:MyTopic:c7fe3a54-ab0e-4ec2-88e0-db410a0f2bee"
}
我目前有这个:
public string FunctionHandler(SNSEvent sns, ILambdaContext context)
SNSEvent
与收到的消息不符。
我应该在 Lambda 函数签名中使用什么事件类型?
当 SNS 向 SQS 队列发送消息时,它将原始消息包装在 SQS 消息信封中,其中包括附加元数据,例如消息 ID、接收句柄和消息属性。
因此,当您订阅 SQS 队列到 SNS 主题,然后配置 SQS 队列来触发 Lambda 函数时, 该函数将收到 SQS 事件;它不会收到 SNS 事件。
您在文档中看到的是传递给 SQS 的 SNS 消息,而不是您需要在函数中处理的包装的 SQS 消息。
这是包装消息的格式 - 请注意原始 SNS 消息(如文档中所示)是在
Body
字段中设置的。
{
"Records": [
{
"MessageId": "76c57c14-985c-4f96-911a-0998b849ad80",
"ReceiptHandle": "xxx",
"Body": "{\n \"Type\" : \"Notification\",\n \"MessageId\" : \"7006b0c3-0a57-5df3-95da-edb8af971e0a\",\n \"TopicArn\" : \"arn:aws:sns:eu-west-1:585470346692:topic\",\n \"Subject\" : \"subject 2\",\n \"Message\" : \"message 2\",\n \"Timestamp\" : \"2023-09-13T11:56:48.310Z\",\n \"SignatureVersion\" : \"1\",\n \"Signature\" : \"xxxx",\n \"SigningCertURL\" : \"https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-xxx.pem\",\n \"UnsubscribeURL\" : \"xxx\"\n}",
"Md5OfBody": "4f2c093ce9ca18e634e56d2d01df1338",
"Md5OfMessageAttributes": null,
"EventSourceArn": "arn:aws:sqs:eu-west-1:xxx:queue",
"EventSource": "aws:sqs",
"AwsRegion": "eu-west-1",
"Attributes": {
"ApproximateReceiveCount": "5",
"AWSTraceHeader": "Root=1-6501a380-a2d7b7a2f246bc50f981003f;Sampled=1",
"SentTimestamp": "1694606208339",
"SenderId": "AIDAISMY7JYY5F7RTT6AO",
"ApproximateFirstReceiveTimestamp": "1694606208339"
},
"MessageAttributes": {}
}
]
}
要处理此问题,您需要使用
SQSEvent
Nuget 包中的预定义
AWS.Lambda.SQSEvents
类。然后,您可以从 SQS 消息信封中提取 SNS 消息。
这是我编写的一个完整工作的 Lambda 示例,应该可以工作:
using Amazon.Lambda.Core;
using Amazon.Lambda.SNSEvents;
using Amazon.Lambda.SQSEvents;
using Newtonsoft.Json;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace SnsToSqsToLambda;
public class Function
{
public async Task FunctionHandler(SQSEvent sqsEvent, ILambdaContext context)
{
foreach (var message in sqsEvent.Records)
{
var snsMessage = JsonConvert.DeserializeObject<SNSEvent.SNSMessage>(message.Body);
await ProcessEventAsync(snsMessage, context);
}
}
private async Task ProcessEventAsync(SNSEvent.SNSMessage snsMessage, ILambdaContext context)
{
context.Logger.LogLine($"Subject: {snsMessage.Subject}");
context.Logger.LogLine($"Message: {snsMessage.Message}");
}
}
测试数据:
aws sns publish \
--topic-arn 'arn:aws:sns:eu-west-1:xxx:topic' \
--subject "subject 1" \
--message "message 1"
aws sns publish \
--region 'region' \
--topic-arn 'arn:aws:sns:eu-west-1:xxx:topic' \
--subject "subject 2" \
--message "message 2"
CloudWatch 输出:
info Subject: subject 1
info Message: message 1
info Subject: subject 2
info Message: message 2