为什么 AWS Lambda 函数总是超时?

Why does AWS Lambda function always time out?

我正在测试 aws lambda,使用 nodejs 和 4.3 版本。我能够在控制台测试中成功完成我的处理程序函数中的所有语句,其中包括连接到我们的 vpc 中的 mongodb 主机。但是,该功能总是超时。我找到了几篇讨论使用回调、设置上下文属性和 IAM 角色权限的帖子和资源,但无论我做什么,它总是以超时告终。当前代码:

'use strict';

var Mongoose = require('mongoose');
var Device = require('./device_model');
var Alarm = require('./alarm_model');
var Event = require('./event_model');

var mongoConnection = process.env.MONGO_URL;

var connection = Mongoose.connect(mongoConnection);

Mongoose.connection.once('open', function() {
    console.log("Connecting to mongo at: " + mongoConnection);
    console.log("Mongoose connection in lambda opened");
});

Mongoose.connection.on('error', function(){
    console.error("Error creating mongoose connection in lambda, exiting!");
    process.exit(1);
});

exports.check_alarms = function(event, context, callback) {

    context.callbackWaitsForEmtpyEventLoop = false;
    console.log("The incoming event: " + JSON.stringify(event));

    var device = null;
    Device.findByUUID(event.uuid, function(error, result){
        if(!error){
            device = result;
            console.log("the device: " + JSON.stringify(device));
            if(event.Ale && event.Ale.length > 0) {
                console.log("We have an alarm, checking if already set");
                callback(null, {"status":"alarms"});
            } else {
                console.log("Event contains no alarm; checking for historic active");
                callback(null, {"status":"no alarms"});
            }
        } else {
            console.log("there's a problem on mongo");
            callback("problem", "status not so good");
        }
    });

    callback(null, {"status":"outside of device find block"});
}

你打错了:

context.callbackWaitsForEmtpyEventLoop = false;

应该是:

context.callbackWaitsForEmptyEventLoop = false;

这是 documentationcallbackWaitsForEmptyEventLoop 行为的描述:

callbackWaitsForEmptyEventLoop

The default value is true. This property is useful only to modify the default behavior of the callback. By default, the callback will wait until the Node.js runtime event loop is empty before freezing the process and returning the results to the caller. You can set this property to false to request AWS Lambda to freeze the process soon after the callback is called, even if there are events in the event loop. AWS Lambda will freeze the process, any state data and the events in the Node.js event loop (any remaining events in the event loop processed when the Lambda function is called next and if AWS Lambda chooses to use the frozen process). For more information about callback, see Using the Callback Parameter.

最小示例:

// Times out due to typo
exports.function1 = (event, context, callback) => {
    setInterval(() => console.log('Long wait'), 100000);
    context.callbackWaitsForEmtpyEventLoop = false;
    callback(null, 'Hello from Lambda');
};

// Returns successfully
exports.function2 = (event, context, callback) => {
    setInterval(() => console.log('Long wait'), 100000);
    context.callbackWaitsForEmptyEventLoop = false;
    callback(null, 'Hello from Lambda');
};

如果有人像我一样对如何将 callbackWaitsForEmptyEventLoop 添加到如下所示的新 Alexa 项目感到困惑:

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
      GetNewFactHandler,
      HelpHandler,
      ExitHandler,
      FallbackHandler,
      SessionEndedRequestHandler,
  )
  .addRequestInterceptors(LocalizationInterceptor)
  .addErrorHandlers(ErrorHandler)
  .lambda();

在此处找到示例项目:https://github.com/alexa/skill-sample-nodejs-fact/blob/master/lambda/custom/index.js

这个解决方案对我有用:

// create a custom skill builder
const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = (event, context, callback) => {
  // we need this so that async stuff will work better
  context.callbackWaitsForEmptyEventLoop = false

  // set up the skill with the new context
  return skillBuilder
    .addRequestHandlers(
      GetNewFactHandler,
      HelpHandler,
      ExitHandler,
      FallbackHandler,
      SessionEndedRequestHandler,
    )
    .addRequestInterceptors(LocalizationInterceptor)
    .addErrorHandlers(ErrorHandler)
    .lambda()(event, context, callback);
}

我从 android 代码触发了一个 lambda。 lambda 正在从 DynamoDB 执行繁重的数据提升操作并生成 JS 对象作为响应。我可以在我的 lambda 日志中看到生成的对象,但是我的 android 副代码总是在等待响应时超时。

超时的原因是同步 lambda 实现的调用负载(请求和响应)限制为 6 MB,异步 lambda 实现为 256 KB。在我的例子中,我有一个异步实现,结果对象超过 256 KB。

没有适当的日志消息说明超过了这个限制,这让我出轨了。参考:https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html

我实施的解决方法是将响应写入 S3 存储桶中的文本文件,并将其引用作为响应传递给 android 端,而不是传递实际对象本身。