【问题标题】:AWS Lambda seems exiting before completionAWS Lambda 似乎在完成之前退出
【发布时间】:2019-01-11 09:45:37
【问题描述】:

我有一个非常简单的 lambda 函数 (nodeJS),它将接收到的事件放入 kinesis 流中。以下是源代码:


    'use strict';

    const AWS = require('aws-sdk');
    const kinesis = new AWS.Kinesis({apiVersion: '2013-12-02'});

    exports.handler = async (event, context, callback) => {
        let body = JSON.parse(event.body);
        let receptionDate = new Date().toISOString();
        let partitionKey = "pKey-" + Math.floor(Math.random() * 10);

        // Response format needed for API Gateway
        const formatResponse = (status, responseBody) => {
            return {
                statusCode: status,
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(responseBody)
            }
        }

        // body.events is an array of events. Just add the reception date in each events.
        for(let e of body.events) {
            e.reception_date = receptionDate;
        }

        console.log("put In kinesis stream");
        let kinesisParams = {
            Data: new Buffer(JSON.stringify(body) + "\n"),
            PartitionKey: partitionKey,
            StreamName: 'event_test'
        };

        kinesis.putRecord(kinesisParams, (err, res) => {
            console.log("Kinesis.putRecord DONE");
            if(err) {
                console.log("putRecord Error:", JSON.stringify(err));
                callback(null, formatResponse(500, "Internal Error: " + JSON.stringify(err)));
            } else {
                console.log("putRecord Success:", JSON.stringify(res));
                callback(null, formatResponse(200));
            }
        });
    };

执行此代码时,cloudwatch 中的日志如下:

START RequestId: 5d4d7526-1a40-401f-8417-06435f0e5408 Version: $LATEST
2019-01-11T09:39:11.925Z    5d4d7526-1a40-401f-8417-06435f0e5408    put In kinesis stream
END RequestId: 5d4d7526-1a40-401f-8417-06435f0e5408
REPORT RequestId: 5d4d7526-1a40-401f-8417-06435f0e5408  Duration: 519.65 ms Billed Duration: 600 ms     Memory Size: 128 MB Max Memory Used: 28 MB  

似乎没有调用 kinesis.putRecord...我在 kinesis 流日志中看不到任何内容。我肯定在某个地方错了,但我不知道在哪里!

【问题讨论】:

    标签: amazon-web-services aws-lambda amazon-kinesis


    【解决方案1】:

    kinesis.putRecord是一个异步操作,当完成(成功或错误)时调用回调(第二个参数)。

    async function 是一个返回 promise 的函数。当这个 Promise 被解决时,Lambda 将完成它的执行,即使还有其他异步操作尚未完成。 由于您的函数不返回任何内容,因此当函数结束时,promise 会立即解决,因此执行将立即完成 - 无需等待您的 async kinesis.putRecord 任务。

    当使用async 处理程序时,您不需要调用回调。相反,你返回你想要的任何东西,或者抛出一个错误。 Lambda 会分别获取并响应。

    所以你有两个选择:

    1. 由于您的代码中没有任何await,因此只需删除async。在这种情况下,Lambda 正在等待事件循环为 emtpy (Unless you explicitly change context.callbackWaitsForEmptyEventLoop)
    2. kinesis.putRecord 更改为:
    let result;
    
    try {
      result = await kinesis.putRecord(kinesisParams).promise();
    } catch (err) {
      console.log("putRecord Error:", JSON.stringify(err));
      throw Error(formatResponse(500, "Internal Error: " + JSON.stringify(err));
    }
    
    console.log("putRecord Success:", JSON.stringify(result));
    return formatResponse(200);
    

    在第二个选项中,lambda 将继续运行直到 kinesis.putRecord 完成。

    有关这种情况下 Lambda 行为的更多信息,您可以在 lambda 容器中的 /var/runtime/node_modules/awslambda/index.js 下查看执行您的处理程序的主要代码。

    【讨论】:

      【解决方案2】:

      @ttulka 你能解释一下吗?提供建议或代码示例? – 安达乔

      这是关于 JavaScript 中异步处理的演变。

      首先,一切都是通过回调完成的,这是最古老的方法。到处使用回调会导致“回调地狱”(http://callbackhell.com)。

      然后引入了 Promises。使用 Promises 看起来有点像使用 Monads,所有东西都打包在一个“盒子”(Promise)中,所以你必须将所有调用链接起来:

      thisCallReturnsPromise(...)
        .then(data => ...)
        .then(data => ...)
        .then(data => ...)
        .catch(err => ...)
      

      这对人类来说有点不自然,因此 ECMAScript 2017 提出了异步函数(async/await)中的语法糖https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

      Async/await 语法允许您像使用普通同步代码一样使用异步承诺:

      const data = await thisCallReturnsPromise(...)
      

      别忘了,await 调用必须在异步函数中:

      async () => {
        const data = await thisCallReturnsPromise(...)
        return await processDataAsynchronouslyInPromise(data)
      }
      

      AWS Lambda 支持 Node.js v8.10,它完全实现了这种语法。

      【讨论】:

        【解决方案3】:

        刚刚找到解决方案:删除“async”关键字使其工作!

            exports.handler = (event, context, callback) => { ... }
        

        【讨论】:

        • 这是一种旧方法
        • @ttulka 你能解释一下吗?提供建议或代码示例?
        • 我不明白为什么这会被否决。这是一种古老的方法,但仍然是一种有效的方法。投反对票的人至少可以就事情如何改进提供一些建设性的反馈吗?
        猜你喜欢
        • 2018-03-25
        • 1970-01-01
        • 1970-01-01
        • 2017-06-18
        • 2015-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多