发布到订阅的 Lambda 函数的 AWS SNS 记录空字段

AWS SNS publishing to a subscribed Lambda function logs null fields

试图 post 到 AWS 论坛,但我的帐户似乎是 "not yet ready",无论如何。

我设置了一个 AWS Lambda 函数(用 Java 编写),它接受 POJO 以允许 JSON 的自动反序列化。我正在使用的测试 JSON 如下所示,它表示 JSON 字符串,一旦一切正常并且 运行.

将从消息的最终源发送
{"sender":"Joe", "id":1, "event":"started", "ticks":2, "time":"20150623T214256Z", "version":"1.0"}

当我通过从 Lambda "test" 控制台发布到它来测试它时,它工作得很好。

我现在正尝试通过将 Lambda 函数订阅到主题来连接 SNS,并且我正在从 SNS 控制台对其进行测试。我尝试使用 "raw data"(未显示任何结果)和使用 "JSON Generator" 数据选项生成的 JSON 发送与上面相同的消息,我是 运行 变成一个问题,当 SNS 将消息发送到 Lambda 函数时,POJO 被实例化,但要么调用默认构造函数,要么调用参数化构造函数并使用所有空值。无论哪种方式,当 Lambda 函数通过调用 POJO 中重写的 toString() 方法来记录消息时,它会为所有变量打印出 null 而没有任何错误消息。同样,SNS 主题配置为登录到 Cloudwatch,它也没有报告任何错误。它获得 HTTP 状态 202。

这是新生成的 JSON 消息。

{
"default": "{\"sender\":\"Joe\", \"id\":1, \"event\":\"started\", \"ticks\":2, \"time\":\"20150623T214256Z\", \"version\":\"1.0\"}", 
"lambda": "{\"sender\":\"Joe\", \"id\":1, \"event\":\"started\", \"ticks\":2, \"time\":\"20150623T214256Z\", \"version\":\"1.0\"}", 
}

以下是日志消息。

Lambda 的日志:

START RequestId: 238a0546-627d-11e5-b228-817bf2a1219a    
Received the following :: We have the following Message{sender=null, id=null, event=null, ticks=null, time=null, version=null}    
END RequestId: 238a0546-627d-11e5-b228-817bf2a1219a   
REPORT RequestId: 238a0546-627d-11e5-b228-817bf2a1219a  Duration: 26.23 ms  Billed Duration: 100 ms     Memory Size: 1536 MB    Max Memory Used: 69 MB  

SNS 日志:

{ "status": "SUCCESS", "notification": { "timestamp": "2015-09-24 05:28:51.079", "topicArn": "arn:aws:sns:us-east-1:256842276575:App", "messageId": "3f5c0fa1-8a50-5ce3-b7c9-41dc060212c8", "messageMD5Sum": "65a5cb6d53616bd385f72177fe98ecc2" }, "delivery": { "statusCode": 202, "dwellTimeMs": 92, "attempts": 1, "providerResponse": "{\"lambdaRequestId\":\"238a0546-627d-11e5-b228-817bf2a1219a\"}", "destination": "arn:aws:lambda:us-east-1:256842276575:function:App-Lambda-Trigger" } }

以下是适用的 Lambda 函数代码:

package com.mycompany;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;

public class LambdaHandler {

    public void Handler(Message msg, Context context) {
        LambdaLogger logger = context.getLogger();
        logger.log("Received the following :: " + msg.toString());
    }
}

public class Message {
    private String sender;
    private Integer id;
    private String event;
    private Integer ticks;
    private String time;
    private Double version;

public Message(String sender, Integer id, String event, Integer ticks, String time, Double version) {
    this.sender = sender;
    this.id = id;
    this.event = event;
    this.ticks = ticks;
    this.time = time;
    this.version = version;
}

... getters/setters ...

public Message() {
}   

@Override
public String toString() {
    return "We have the following Message{" + "sender=" + getSender() + ", id=" + id + ", event=" + event + ", ticks=" + ticks + ", time=" + time + ", version=" + version + '}';
}

在做了一些挖掘并查看了一些 javascript 示例之后(我似乎找不到任何订阅 SNS 的函数的 Java 示例),它们似乎都收到了 "event".我在 AWS 的 Github 存储库中找到了一个 Java class SNSEvent (https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/SNSEvent.java),但它不在官方 Java 文档中。 None 的 AWS 文档我已经能够找到文档 Java Lambda 函数设置以接收反序列化的 POJO(我不敢相信这是不常见的)但我找不到任何东西指定 SNS 主题向 Lambda 函数发送的对象类型,如果事实上我不应该期望 POJO 类型。

有人可以澄清一下,我的 Lambda 函数应该接收什么类型的对象?有人可以提供一些示例代码吗?

如有任何帮助,我们将不胜感激。

编辑 1

我根据建议修改了我的函数以接受 SNSEvent 和 Context 对象,但我的函数抛出了以下异常:

Error loading method handler on class com.app.LambdaHandler: class java.lang.NoClassDefFoundError java.lang.NoClassDefFoundError: com/amazonaws/services/lambda/runtime/events/SNSEvent 
at java.lang.Class.getDeclaredMethods0(Native Method) 
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) 
at java.lang.Class.privateGetPublicMethods(Class.java:2902) 
at java.lang.Class.getMethods(Class.java:1615) Caused by: java.lang.ClassNotFoundException: com.amazonaws.services.lambda.runtime.events.SNSEvent 
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

好像运行环境不识别SNSEvent?

我认为您应该更改两件事:

  1. 您的消息 class 不遵循 Lambda 将用于反序列化事件对象的预期 Lambda POJO format 的 getX/setX 访问器。
  2. 如果您的活动来自 SNS,它将遵循通用 SNS 对象格式,而不是您的自定义格式。您将必须检查 SNS 事件以在 Message 中提取您的自定义数据,然后单独解析它。在 Actions > Configure sample event 下查看 Lambda 中的 SNS 事件模板。

这是一个示例 Lambda 函数,用于处理 Java 中的 SNS 事件,使用 AWS Lambda Java Support Libraries

package example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.events.SNSEvent;

public class SNSEventHandler {

    public String handleSNSEvent(SNSEvent event, Context context) {
        LambdaLogger logger = context.getLogger();
        for (SNSEvent.SNSRecord record : event.getRecords()) {
            SNSEvent.SNS sns = record.getSNS();
            logger.log("handleSNSEvent received SNS message " + sns.getMessage());
        }
        return "handleSNSEvent finished";
    }

}

SNSEvent data model 表明多个事件可能同时到达处理程序,因此示例显示对它们进行迭代而不是仅假设一个。我还没有在实践中看到这一点,但我的使用量一直很低。