如何在AWS Lambda中等待异步操作?

st7*_*t78 46 node.js aws-lambda

我正在尝试在S3中处理上传的文件.由于getObject是异步主函数在处理完成之前结束,因此AWS在3-4秒内杀死lambda.

更糟糕的是,处理方法中还包含异步操作 - 它会进行http调用.

在高级别,我的代码看起来像:

exports.handler = function(event, context) {
    // Get the object from the event and show its content type
    var bucket = event.Records[0].s3.bucket.name;
    var key = event.Records[0].s3.object.key;
    var params = {
        Bucket: bucket,
        Key: key
    };
    s3.getObject(params, function(err, data) {
        if (err) {
             ...
        } else {
            processFile(data.Body.toString(), 0);
            console.log("ok");
        }
    });
    //need to wait here till processFile is done
};

processFile = function(content, start) {
  ... build url to call
  http.get(url, function(res) {  
    console.log("Got response: " + res.statusCode + ");
    processFile(content, start + 1);
  });
}
Run Code Online (Sandbox Code Playgroud)

我发现nodejs中存在异步但亚马逊不包含它; 两者都需要('async')或require('sleep)导致错误.

Lambda超时配置为60秒,但它在3-4秒内退出.

Neo*_*Neo 34

开发人员的生活在不断变化,我们现在在lambda上有NodeJS 8.对于现在看这个的人,请查看:

Lambda节点8.10与节点6.10的比较:https: //aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

JS异步的基础知识:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

更多aws sdk示例:https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html

有关wtf .promise()方法的详细信息位于第一个链接:https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Request.html#promise-property

这是我对一个基本示例的看法(尝试粘贴到您自己的lambda中):

exports.handler = async (event) => {    
    function wait(){
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve("hello"), 2000)
        });
    }
    
    console.log(await wait());
    console.log(await wait());
    console.log(await wait());
    console.log(await wait());
    console.log(await wait());
    console.log(await wait());
    
    return 'exiting'
};
Run Code Online (Sandbox Code Playgroud)

以上产量:

在此输入图像描述

你可以看到它等了12秒而没有杀死我的功能:)

每次等待TODO不止一件事,使用Promise.all([])语法如下:

exports.handler = async (event) => {
    var uploadPromises = [];
    folder.files.forEach(file => {
        uploadPromises.push( s3.putObject({
            Bucket: "mybucket",
            Key: file.name,
            Body: file.data
        }).promise());
    });

    await Promise.all(uploadPromises);
    return 'exiting'
}; 
Run Code Online (Sandbox Code Playgroud)

下面的Orignal答案

我的手上也有同样的问题.

问题是javascript事件循环是空的,所以Lambda认为它已经完成了.

这就是我解决这个问题的方法.我意识到这不是理想的,我希望有更好的方法,但我不想a)添加库,b)协调lambda调用,或c)切换到另一种语言.

在一天结束时,它的工作原理.

    exports.handler = (event, context, callback) => {
        var response;
        var callBackCount;

        /*
        Ensures the javascript event loop is never empty.
        This is the key to keeping lambda from exiting early
        */
        setInterval(function(){}, 1000);

        /*
        Tell lambda to stop when I issue the callback.
        This is super important or the lambda funciton will always go until it hits the timeout limit you set.
        */
        context.callbackWaitsForEmptyEventLoop = false;
        
        //My way of determining when I'm done with all calls
        callBackCount = 0;
      
        //My info to return
        response = "";
        
        //Various functions that make rest calls and wait for a response
        asyncFunction1();
        asyncFunction2();
        asyncFunction3();

        //Same for asyncFunction 2 and 3
        function asyncFunction1(){
          response += callBackResponseForThisMethod;
      
          returnResponse();
        }

        function returnReponse(){
            callBackCount++;

            if(callBackCount == 3){
              //Lambda will stop after this as long as    context.callbackWaitsForEmptyEventLoop was set to false 
              callback(null, JSON.stringify(response));
            }
        }

    };
Run Code Online (Sandbox Code Playgroud)

http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html


Jos*_*gia 7

async不包括但这并不意味着你不能自己添加它.只需在本地添加包(npm install async),并node_modules在上传Lambda函数之前在ZIP中包含该文件夹.

如果你想单独处理dev依赖项(例如:test,aws-sdk在本地执行你的函数等),你可以devDependencies在你的下面添加它们package.json.此外,如果您想自动化开发,测试,部署和推广代码的过程,这两个回购将变得非常方便.

用于测试,打包和部署lambda的Grunt例程

用于运行和部署lambda函数的命令行工具


hon*_*let 7

使用异步/等待

let AWS = require('aws-sdk');
let lambda = new AWS.Lambda();
let data;
exports.handler = async (event) => {
    try {
        data = await lambda.getAccountSettings().promise();
    }
    catch (err) {
        console.log(err);
        return err;
    }
    return data;
};
Run Code Online (Sandbox Code Playgroud)


rk2*_*rk2 5

我认为你的lambda函数应该以context.done()调用结束.例如,尝试以这种方式添加它:

s3.getObject(params, function(err, data) {
    if (err) {
         ...
        context.done("Error: " + err.stack);
    } else {
        processFile(data.Body.toString(), 0);
        console.log("ok");
        context.done(null, "success");
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 在s3.getObject回调之后你有context.done吗?您是否尝试从上一个处理程序中删除context.done并将其仅放在s3.getObject回调中,就像我上面显示的那样?甚至在s3.getObject回调完成之前,可能会在回调之外调用context.done. (2认同)

Sil*_*rge 5

将Lambda想象成一个可以在一定时间内运行的程序.您进行异步调用的事实很好,因为(虚拟)处理器可能会交错这些调用.但是,如果Lambda程序的任何部分比分配的时间花费的时间更长,那么执行将失败.这是你做出的妥协,也是亚马逊赚钱的方式; 通过卖给你更多的时间或记忆.

要解决这个问题,您可以增加分配Lambda函数的内存.这不仅可以增加RAM,还可以提高虚拟处理器的速度.您可以做的另一件事是增加超时.AWS Lambda现在允许最多512 MB的RAM和最多5分钟的处理时间.截至这篇文章,这些数字可能已经改变,所以请查看最新的限制.要更改此设置,请转到您的功能,然后进行配置,最后进行高级操作.


ped*_*pio 5

如果您还想使用require('async');pack或require('sleep');pack,则需要将函数作为以下zip文件上传:

创建部署程序包(Node.js)

Zip 我在这个问题中也解释了该文件夹的所有内容:

适用于Alexa Javascript的AWS Lambda函数中的MQTT

关于同步处理,您可以require('async');正常使用,只是使用如下async.series功能:

    async.series([
    function(callback) {
        // to do the function 1
        callback();
    },
    function(callback) {
        // to do the function 2
        callback();
    },
    function(callback) {
        // to do the function 3
        callback();
    }
], function(err) {
    // to do the function if any error happens...

    if (err) {
        //...
    }
    //....
});
Run Code Online (Sandbox Code Playgroud)

这样,该lambda功能将同步工作。

希望对您有帮助。