我应该使用什么类型的 Lambda 事件来处理从 SQS 队列收到的 SNS 消息?

问题描述 投票:0回答:1

我有一个 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 函数签名中使用什么事件类型?

amazon-web-services aws-lambda amazon-sqs amazon-sns aws-sdk-net
1个回答
0
投票

当 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 
© www.soinside.com 2019 - 2024. All rights reserved.