Javascript 使用S3.getObject在Lambda上创建节点

Javascript 使用S3.getObject在Lambda上创建节点,javascript,node.js,amazon-s3,aws-lambda,Javascript,Node.js,Amazon S3,Aws Lambda,所以,我把头撞在墙上,想弄清楚我到底做错了什么。我正在使用NodeJS 6.10编写一个Lambda函数。该函数应该从我的一个S3存储桶中检索多个图像并对其进行处理。我接受JavaScript的异步特性,或者尝试,无论如何,允许这些并发发生,然后在所有这些都完成后等待并做一些事情。我已经将这里的代码提炼到我能写的最低限度,并且仍然重现我所看到的问题。问题是没有一个图像被检索到——事实上,没有迹象表明Lambda函数曾经试图检索它们,也没有迹象表明回调曾经被触发 代码如下: console.log

所以,我把头撞在墙上,想弄清楚我到底做错了什么。我正在使用NodeJS 6.10编写一个Lambda函数。该函数应该从我的一个S3存储桶中检索多个图像并对其进行处理。我接受JavaScript的异步特性,或者尝试,无论如何,允许这些并发发生,然后在所有这些都完成后等待并做一些事情。我已经将这里的代码提炼到我能写的最低限度,并且仍然重现我所看到的问题。问题是没有一个图像被检索到——事实上,没有迹象表明Lambda函数曾经试图检索它们,也没有迹象表明回调曾经被触发

代码如下:

console.log('Executing testImg method.');
var aws = require('aws-sdk');
var s3 = new aws.S3();

var imgData = {};

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

    var imgs = ['img_1', 'img_2', 'img_3', 'img_4', 'img_5', 'img_6', 'img_7', 'img_8'];
    var imgPromises = [];
    console.log('Grabbing images: ' + imgs);
    imgs.forEach(function(img) {
        console.log(img);
        var myPromise = s3.getObject({
            Bucket: 'photoBucket',
            Key: 'images/' + img + '.png'
        }).promise();
        imgPromises.push(myPromise);
        myPromise.then(function(result) {
            console.log('Got ' + img);
            imgData[img] = result.Body;
        });
    });
    Promise.all(imgPromises).then(function() {
        console.log(imgData);
        context.succeed();
    });

}
这是Lambda的输出:

START RequestId: <UUID> Version: $LATEST
2017-05-21T18:53:31.187Z    <UUID>  Grabbing images: img_1,img_2,img_3,img_4,img_5,img_6,img_7,img_8
2017-05-21T18:53:31.187Z    <UUID>  img_1
2017-05-21T18:53:31.625Z    <UUID>  img_2
2017-05-21T18:53:31.648Z    <UUID>  img_3
2017-05-21T18:53:31.706Z    <UUID>  img_4
2017-05-21T18:53:31.707Z    <UUID>  img_5
2017-05-21T18:53:31.708Z    <UUID>  img_6
2017-05-21T18:53:31.766Z    <UUID>  img_7
2017-05-21T18:53:31.767Z    <UUID>  img_8
END RequestId: <UUID>
REPORT RequestId: <UUID>    Duration: 10002.24 ms   Billed Duration: 10000 ms   Memory Size: 128 MB Max Memory Used: 80 MB  
2017-05-21T18:53:41.173Z <UUID> Task timed out after 10.00 seconds
START RequestId:Version:$LATEST
2017-05-21T18:53:31.187Z抓取图像:img_1、img_2、img_3、img_4、img_5、img_6、img_7、img_8
2017-05-21T18:53:31.187Z图片1
2017-05-21T18:53:31.625Z img_2
2017-05-21T18:53:31.648Z img_3
2017-05-21T18:53:31.706Z img_4
2017-05-21T18:53:31.707Z img_5
2017-05-21T18:53:31.708Z img_6
2017-05-21T18:53:31.766Z图片7
2017-05-21T18:53:31.767Z图片8
结束请求ID:
报告请求ID:持续时间:10002.24毫秒计费持续时间:10000毫秒内存大小:128 MB最大使用内存:80 MB
2017-05-21T18:53:41.173Z任务在10秒后超时
从输出中可以看到,console.log(img)行在打印图像名称的地方运行。但是,单个.then()块中的任何代码都不会运行(例如,console.log('get'+img)),最终Promise.all块中的任何代码都不会运行(打印出整个数组,并调用succeed函数终止该函数)

此外,我还尝试了其他一些方法:

  • 使用NodeJS+lambda-local在本地运行代码,效果很好
  • 在没有lambda local的NodeJS中运行类似的代码。效果很好
  • 使用显式凭据在Lambda上运行代码,而不是允许它使用Lambda角色。在AWS Lambda上仍然失败
  • 下载一个图像在Lambda中工作得非常好——它似乎不喜欢多次调用getObject,尽管我在文档中找不到任何迹象表明这是一件坏事
  • 我尝试从循环中删除单个myPromise.then()调用,并在Promises.all()块中执行所有操作,同样,这不会导致代码实际在AWS中运行
我可以将它们链接在一起,使它们都同步发生,但1)很难以动态方式这样做(不知道需要提前处理的文件数量),2)这似乎与Async JS目前的做法背道而驰


如果有任何提示,我们将不胜感激。

好的,Mark B关于S3需要访问公共互联网资源的评论非常正确,以下是三种可能的解决方案:

  • 将Lambda函数移动到公共子网,该子网具有通过IGW到Internet的路由。我真的不想走这条路,因为没有理由公开这些实例,但这是一种选择
  • 配置NAT网关(以前称为NAT实例)并配置路由表,以允许流量通过该方法输出到Internet端点。不幸的是,NAT网关会产生费用,我不想每月增加账单
  • 我最终使用的方法是将S3端点添加到我的私有子网内的VPC中,然后配置路由表、安全组和策略,以便私有子网内的项目可以访问该S3端点。这很好用

马克,再次感谢您向正确的方向轻推。

您的代码只处理成功的场景。您需要在每个承诺中添加一个
.catch()
,或者在
.then()
中添加第二个函数,以捕获并打印出任何错误消息,我相信这将为您提供一个非常好的线索,了解到底发生了什么。另外,您是否将Lambda函数放置在没有NAT网关的VPC中(这可能会导致S3API调用超时)?谢谢。我希望你已经发布了这个解决方案,这样我可以为你标记它正确。我曾经有过一些捕获/错误代码,但是默认的连接超时时间比大多数Lambda函数的限制都要长,所以根本就没有检查错误代码。我将Lambda函数放在VPC中以访问私有数据库服务器,甚至没有想到S3端点是外部的。正确放置NAT网关和一些减少的HTTP连接超时解决了这一问题。谢谢