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

时间:2015-07-26 05:18:24

标签: node.js aws-lambda

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

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

在高级别,我的代码如下:

remove("/path/to/foo.txt");

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

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

7 个答案:

答案 0 :(得分:28)

开发者的生活在不断变化,我们现在在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'
};




以上产量:

enter image description here

你可以看到它等了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'
}; 

下面的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));
            }
        }

    };




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

答案 1 :(得分:7)

async不包括在内,但这并不意味着您无法自行添加。 只需在本地添加包(npm install async),并在上传Lambda函数之前在ZIP中包含node_modules文件夹。

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

Grunt routine to test, package and deploy your lambdas

Command line tool for running and deploying your lambda functions

答案 2 :(得分: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");
    }
});

答案 3 :(得分:5)

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

要解决这个问题,您可以增加分配Lambda功能的内存。这不仅可以增加RAM,还可以提高虚拟处理器的速度。您可以做的另一件事是增加超时。 AWS Lambda现在允许最多512 MB的RAM和最多5分钟的处理时间。截至本帖子,这些数字可能已更改,因此请检查here以获取最新限制。要更改此设置,请转到您的功能,然后进行配置,最后进入高级。

答案 4 :(得分:5)

使用async / await

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;
};

答案 5 :(得分:4)

如果您还想使用require('async');打包或require('sleep');打包,则需要将您的功能上传为zip这样的文件:

Creating a Deployment Package (Node.js)

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

MQTT in AWS Lambda function for Alexa Javascript

关于同步处理,您可以正常使用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) {
        //...
    }
    //....
});

这样lambda函数将同步工作。

我希望能帮助你。

答案 6 :(得分:0)

您可能想要拨打synchronous电话;因为您似乎在同一个lambda函数中处理文件。

如果由于某种原因你想要回电;你可以通过直接调用lambda或通过产生lambda事件的东西来做到这一点。请注意,lambda函数应该是无状态的;所以你应该传递所有需要的信息。