0

我正在使用 AWS Lambda 和 MongoDB 构建 Facebook 聊天机器人。目前,我的应用程序非常简单,但我正在尝试确定基础知识,然后再处理复杂的内容。

我了解 AWS Lambda 是无状态的,但我已经阅读了在处理程序中添加以下行以及在处理程序外部初始化的变量,我不必在每个请求上建立数据库连接。

context.callbackWaitsForEmptyEventLoop = false;

(我从这篇文章中读到了这个;https://www.mongodb.com/blog/post/optimizing-aws-lambda-performance-with-mongodb-atlas-and-nodejs

我在下面添加我的整个代码

'use strict'

const
axios = require('axios'),
mongo = require('mongodb'),
MongoClient = mongo.MongoClient,
assert = require('assert');

var VERIFY_TOKEN = process.env.VERIFY_TOKEN;
var PAGE_ACCESS_TOKEN = process.env.PAGE_ACCESS_TOKEN;
var MONGO_DB_URI = process.env.MONGO_DB_URI;
let cachedDb = null;
let test = null;

exports.handler = (event, context, callback) => {
var method = event.context["http-method"];
context.callbackWaitsForEmptyEventLoop = false;
console.log("test :: " + test);
if (!test) {
    test = "1";
}

// process GET request --> verify facebook webhook
if (method === "GET") {
    var queryParams = event.params.querystring;
    var rVerifyToken = queryParams['hub.verify_token']
    if (rVerifyToken === VERIFY_TOKEN) {
        var challenge = queryParams['hub.challenge'];
        callback(null, parseInt(challenge))
    } else {
        var response = {
            'body': 'Error, wrong validation token',
            'statusCode': 403
        };
        callback(null, response);
    }
    // process POST request --> handle message
} else if (method === "POST") {
    let body = event['body-json'];

    body.entry.map((entry) => {
        entry.messaging.map((event) => {
            if (event.message) {
                if (!event.message.is_echo && event.message.text) {
                    console.log("BODY\n" + JSON.stringify(body));
                    console.log("<<MESSAGE EVENT>>");
                    // retrieve message
                    let response = {
                            "text": "This is from webhook response for \'" + event.message.text + "\'"
                        }
                        // facebook call
                    callSendAPI(event.sender.id, response);

                    // store in DB
                    console.time("dbsave");
                    storeInMongoDB(event, callback);
                }
            } else if (event.postback) {
                console.log("<<POSTBACK EVENT>>");
            } else {
                console.log("UNHANDLED EVENT; " + JSON.stringify(event));
            }

        })
    })
}
}

function callSendAPI(senderPsid, response) {
    console.log("call to FB");
    let payload = {
        recipient: {
            id: senderPsid
        },
        message: response
    };
    let url = `https://graph.facebook.com/v2.6/me/messages?access_token=${PAGE_ACCESS_TOKEN}`;
    axios.post(url, payload)
        .then((response) => {
            console.log("response ::: " + response);
        }).catch(function(error) {
            console.log(error);
        });
}

function storeInMongoDB(messageEnvelope, callback) {
    console.log("cachedDB :: " + cachedDb);
    if (cachedDb && cachedDb.serverConfig.isConnected()) {
        sendToAtlas(cachedDb.db("test"), messageEnvelope, callback);
    } else {
        console.log(`=> connecting to database ${MONGO_DB_URI}`);
        MongoClient.connect(MONGO_DB_URI, function(err, db) {
            assert.equal(null, err);
            cachedDb = db;
            sendToAtlas(db.db("test"), messageEnvelope, callback);
        });
    }
}

function sendToAtlas(db, message, callback) {
    console.log("send to Mongo");
    db.collection("chat_records").insertOne({
        facebook: {
            messageEnvelope: message
        }
    }, function(err, result) {
        if (err != null) {
            console.error("an error occurred in sendToAtlas", err);
            callback(null, JSON.stringify(err));
        } else {
            console.timeEnd("dbsave");
            var message = `Inserted a message into Atlas with id: ${result.insertedId}`;
            console.log(message);
            callback(null, message);
        }
    });
}

我按照指示做了所有事情,并参考了更多类似的案例,但不知何故,在每个请求中,“cachedDb”值不会从先前的请求中保存,并且应用程序正在重新建立连接。

然后我还读到不能保证 Lambda 函数在多个请求上使用相同的容器,所以我创建了另一个全局变量“test”。“test”变量值在第二个请求中记录为“1”,这意味着它使用的是同一个容器,但同样,“cachedDb”值没有保存。

我在这里想念什么?

提前致谢!

4

1 回答 1

-1

In short AWS Lambda function is not a permanently running service of any kind.

So, far I know AWS Lambda works on idea - "one container processes one request at a time".

It means when request comes and there is available running container for the Lambda function AWS uses it, else it starts new container.

If second request comes when first container executes Lambda function for first request AWS starts new container. and so on...

Then there is no guarantee in what container (already running or new one) Lambda function will be executed, so... new container opens new DB connection.

Of course, there is an inactivity period and no running containers will be there after that. All will start over again by next request.

于 2018-06-11T15:51:28.193 回答