Javascript Node.js/AWS Lambda在发送SNS推送之前结束

Javascript Node.js/AWS Lambda在发送SNS推送之前结束,javascript,node.js,amazon-web-services,aws-lambda,Javascript,Node.js,Amazon Web Services,Aws Lambda,也许擅长Node.js的人可以解决这个问题。 在Amazon Web服务上编写和测试我的代码时,我注意到Lambda有时会在SNS发布之前终止该函数。我认为问题可能正在发生,因为“context.done”很早就被调用了。但从逻辑上讲,这种情况不应该发生。重要信息:代码工作正常!(除了我前面提到的那件事) 代码的基本思想是:只要DynamoDB中的条目发生变化,Lambda就会做出反应,并通过SNS推送通知“所有者” 谢谢你的帮助 此代码正在Lambda实例上运行 console.log('L

也许擅长Node.js的人可以解决这个问题。

在Amazon Web服务上编写和测试我的代码时,我注意到Lambda有时会在SNS发布之前终止该函数。我认为问题可能正在发生,因为“context.done”很早就被调用了。但从逻辑上讲,这种情况不应该发生。重要信息:代码工作正常!(除了我前面提到的那件事)

代码的基本思想是:只要DynamoDB中的条目发生变化,Lambda就会做出反应,并通过SNS推送通知“所有者”

谢谢你的帮助


此代码正在Lambda实例上运行

console.log('Loading function');
var aws = require('aws-sdk');
var doc = require('dynamodb-doc');
var dynamo = new doc.DynamoDB();
exports.handler = function(event, context){

    var target = null;
    var status = null;

    event.Records.forEach(function(record){

            console.log("Function Invoked");
            console.log("Function Event: "+record.eventName);

            if(record.eventName === "MODIFY")
            {
                db_record_exists(record, function(r) {
                    if (r) {

                        if(r.handle == "true"){
                            creator = r.creator;
                            participant = r.participant;

                            creator = JSON.stringify(creator);
                            status = JSON.stringify(record.dynamodb.NewImage.status.S);
                            creator = creator.replace(/"/g, "");
                            status = status.replace(/"/g, "");

                            participant = JSON.stringify(record.dynamodb.NewImage.participant.S);
                            participant = participant.replace(/"/g, "");

                            console.log("creator: "+ creator);
                            console.log("status: "+ status);
                            console.log("participant is: "+ participant);

                            getCredentialsMovement(creator,participant,function(response){
                                console.log("RESPONSE: "+ response);

                                sendSNSmovement(response, status, context);

                            });

                        }else{
                            context.done();
                        }
                    }
                });
            }else if(record.eventName == "INSERT"){
                db_record_exists(record, function(r) {
                    if (r) {

                        if(r.handle == "true"){
                            creator = r.creator;
                            participant = r.participant;

                            creator = JSON.stringify(creator);
                            status = JSON.stringify(record.dynamodb.NewImage.status.S);
                            creator = creator.replace(/"/g, "");
                            status = status.replace(/"/g, "");

                            participant = JSON.stringify(record.dynamodb.NewImage.participant.S);
                            participant = participant.replace(/"/g, "");

                            console.log("creator: "+ creator);
                            console.log("status: "+ status);
                            console.log("participant is: "+ participant);

                            getCredentialsInvitation(creator,participant,function(response){
                                console.log("RESPONSE: "+ response);

                                sendSNSinvitation(response, context);

                            });

                        }else{
                            context.done();
                        }
                    } else context.done();
                });
            }else{
                context.done();
            }
        }
    );
};



function db_record_exists(record, callback){

    var users = {};
    users.creator = record.dynamodb.NewImage.creator.S;
    users.participant = record.dynamodb.NewImage.participant.S;

    if(users.creator != users.participant){
        users.handle = "true";
    }else{
        users.handle = "false";
    }

    callback(users);
}

function shutdown(context){
    context.done();
}


function sendSNSmovement(creator_information, status, context){

    var sns = new aws.SNS();
    var payload_negative = creator_information.name + " has declined your event!";
    var payload_positive = creator_information.name + " has accepted your event!";
    //var payload_positive = "Positive";

    var payload_accepted = {
        "GCM": "{ \"data\": { \"message\": \"Your event has been accepted!!\"} }"
    };

    var payload_declined = { "GCM": "{ \"data\":  { \"message\": \"Your event has been declined!\" } }" };

    //   console.log("Standart Message as JSON: "+ payload_declined.GCM);

    payload_declined.GCM = "{ \"data\": { \"message\": \""+payload_negative+"\" } }";
    payload_accepted.GCM = "{ \"data\": { \"message\": \""+payload_positive+"\" } }";


    //   console.log("Standart Message as JSON: "+ payload_declined.GCM);
    //  console.log("Standart Message as String: "+ JSON.stringify(payload_declined));


    payload_accepted = JSON.stringify(payload_accepted);
    payload_declined = JSON.stringify(payload_declined);

    var payload;

    if(status == "true"){
        payload = payload_accepted;
    }else{
        payload = payload_declined;
    }


    var params = {
        TargetArn: creator_information.arn,
        MessageStructure: 'json',
        Message: payload
    };

    sns.publish(
        params, function(err, data) {
            if (err) {
                console.log(err.stack);
// Notify Lambda that we are finished, but with errors

                context.done(err, 'Brians Function Finished with Errors!');

            }else{
                console.log('push sent');
                console.log(data);
// Notify Lambda that we are finished

                context.done();
            }

        });
}

function sendSNSinvitation(creator_information,context){

    var sns = new aws.SNS();
    var payload_message = creator_information.name + " has invited you to an event!";

    var payload = {
        "GCM": "{ \"data\": { \"message\": \"Your event has been accepted!!\"} }"
    };


    payload.GCM = "{ \"data\": { \"message\": \""+payload_message+"\" } }";



    payload = JSON.stringify(payload);


    var params = {
        TargetArn: creator_information.arn,
        MessageStructure: 'json',
        Message: payload
    };

    sns.publish(
        params, function(err, data) {
            if (err) {
                console.log(err.stack);

// Notify Lambda that we are finished, but with errors

                context.done(err, 'Brians Function Finished with Errors!');

            }else{
                console.log('push sent');
                console.log(data);
// Notify Lambda that we are finished

                context.done();
            }
        });
}

function getCredentialsMovement(creator,participant,callback) {

    var params_name = {

        TableName : "users",
        Key : {
            "id" : participant
        },

        ProjectionExpression: 'person_name'

    };
    var params_arn = {

        TableName : "users",
        Key : {
            "id" : creator
        },

        ProjectionExpression: 'arn'

    };

    dynamo.getItem(params_name, function(err, data) {

        var response = {};

        if (err) {
            console.log(err);
            return err;
        }
        else {
            console.log("creators name is: "+data.Item.person_name);
            response.name = data.Item.person_name;
            dynamo.getItem(params_arn, function(err, data) {


                if (err) {
                    console.log(err);
                    return err;
                }
                else {
                    console.log(data.Item.arn);

                    response.arn = data.Item.arn;

                    return callback(response);
                }
            });


        }
    });

}
function getCredentialsInvitation(creator,participant,callback) {

    var params_name = {

        TableName : "users",
        Key : {
            "id" : creator
        },

        ProjectionExpression: 'person_name'

    };
    var params_arn = {

        TableName : "users",
        Key : {
            "id" : participant
        },

        ProjectionExpression: 'arn'

    };

    dynamo.getItem(params_name, function(err, data) {

        var response = {};

        if (err) {
            console.log(err);
            return err;
        }
        else {
            console.log("creators name is: "+data.Item.person_name);
            response.name = data.Item.person_name;
            dynamo.getItem(params_arn, function(err, data) {


                if (err) {
                    console.log(err);
                    return err;
                }
                else {
                    console.log(data.Item.arn);

                    response.arn = data.Item.arn;

                    return callback(response);
                }
            });


        }
    });

}

我不知道您的代码到底出了什么问题,但我有一些调试建议:

  • 为Lambda函数打开CloudWatch日志
  • 确保代码中每个唯一的路径都有不同的日志消息,这样您就可以区分哪些场景有效,哪些不有效
  • 我统计了对
    context.done()
    的9个调用,它们分布在多个函数中。您应该将其减少到一个或两个(成功/错误)。不要让每个函数调用
    context.done()
    ,而是让它们使用回调将状态返回给顶级处理程序
  • 您可以考虑使用承诺或库,使回调链更容易理解。 似乎contex.done()调用在逻辑上是不分开的。您有一个for循环,其中包含异步调用。如果事件中有多条记录,则可能会同时处理这些记录,其中一条记录可能会调用context.done(),而另一条记录仍然未完成


    假设此代码有两个修改事件,对于第一个db_记录,exist函数返回r.handle=“true”,第二个返回false。第一个将继续异步调用getCredentials(dynamo.getItem)。同时,将处理第二条记录并调用context.done(),从而在不等待dynamo响应的情况下结束lambda函数

    谢谢您的回答。这些东西我都试过了。Amazon的一位工程师告诉我,如果我使用多个“context.done()”调用,只要它们在逻辑上是分开的,就没有关系。你还有什么进一步的建议吗?如果只有一个语句,那么验证逻辑就更容易了。尝试使用MODIFY运行100次,使用INSERT事件运行100次,并计算每个路径的成功率。这可能会帮助您了解问题的类型,以及应该在代码中查找的位置。