How to wait for async actions inside AWS Lambda?
我正在尝试处理S3中上载的文件。因为getobject是异步的,所以主函数在处理完成之前结束,而aws在3-4秒内杀死lambda。
更糟糕的是,处理方法中还包含异步操作——它进行HTTP调用。
从高层来看,我的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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); }); } |
我发现nodejs中有async,但它不包含在Amazon中;两者都要求("async")或要求("sleep")会导致错误。
lambda超时配置为60秒,但在3-4秒后退出。
开发人员的生活在不断变化,我们现在在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 Async基础:https://developer.mozilla.org/en-us/docs/web/javascript/reference/statements/async_函数
更多的AWS SDK示例:https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-commandes.html
有关wtf.promise()方法的详细信息,请参见第一个链接:https://docs.aws.amazon.com/awsjavascriptssdk/latest/aws/request.html promise属性
下面是我的一个基本示例(尝试粘贴到您自己的lambda中):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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' }; |
上述结果:
。
如你所见,它等待了12秒,却没有破坏我的功能:)
TODO每个wait有多个内容,请使用promise.all([])语法,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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' }; |
号
原始答案如下
我手上也有同样的问题。
问题是javascript事件循环是空的,所以lambda认为它已经完成了。
这就是我解决这个问题的方法。我意识到这并不理想,我希望有更好的方法,但我不想a)添加库,b)协调lambda调用,或c)切换到另一种语言。
在一天结束的时候,它开始工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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 2 3 4 5 6 7 8 9 10 11 12 13 | 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; }; |
。
不包括
如果要单独处理dev依赖项(如test、
用于测试、打包和部署lambda的grunt例程
运行和部署lambda函数的命令行工具
把lambda简单地看作是一个可以在一定时间内运行的程序。您进行异步调用的事实很好,因为(虚拟)处理器可能会交错这些调用。但是,如果lambda程序的任何部分的完成时间比分配的时间长,那么,执行将失败。这是你所做的妥协,也是亚马逊如何赚钱;通过卖给你更多的时间或记忆。
为了解决这个问题,你可以增加内存,你的lambda函数被分配了。这不仅提高了RAM,而且还提高了虚拟处理器的速度。您可以做的另一件事是增加超时。AWS lambda现在允许您最多512 MB的RAM和最多5分钟的处理时间。从这篇文章开始,这些数字可能已经改变了,所以请检查这里的最新限制。要更改此设置,请转到您的功能,然后转到配置,最后转到高级。
我认为lambda函数应该以context.done()调用结束。例如,尝试通过以下方式添加:
1 2 3 4 5 6 7 8 9 10 | 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"); } }); |
如果您还想使用
创建部署包(node.js)
用于Alexa javascript的AWS lambda函数中的mqtt
关于同步处理,您可以正常使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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或通过一些可以生成lambda事件的方法来实现这一点。注意lambda函数应该是无状态的;所以您应该传递所有需要的信息。