在主程序之前在lambda中加载S3文件

我正在写一个lambda函数,需要加载一个存储在S3中的密钥。 它不会经常改变,所以我宁愿不要每次调用lambda函数都抓住它,所以我想在容器被启动时加载一次,然后在lambda容器的生命周期中保存该值。

但是,由于asynchronous方法getObject,这导致了一个问题,因为在运行main module.export代码时(特别是如果这是第一次运行并且正在创build容器),文件可能未被加载。

我已经使用setTimeout实现了一个解决方法,但是我想看看这个推荐的方法是什么,而且我的方法有什么问题,因为它感觉不对!

示例代码:

var AWS = require('aws-sdk') var s3 = new AWS.S3(); var fileLoaded = false; var params = { Bucket: 'bucket-name', Key: 'file-name' }; s3.getObject(params, function(err, data) { if (err) console.log(err, err.stack); // an error occurred else { console.log('File loaded from S3'); fileLoaded = true; } }); exports.handler = (event, context, callback) => { console.log('I am in the main procedure, but i might not have the file yet') waitForFileLoadBeforeDoingSomething(event, context, callback) }; function waitForFileLoadBeforeDoingSomething(event, context, callback){ if(!fileLoaded){ console.log('No file available to me yet, we will sleep') setTimeout(function(){ waitForFileLoadBeforeDoingSomething(event, context, callback) }, 300) } else { console.log('I have the file!') doStuff(event, context, callback) } } function doStuff(event, context, callback){ console.log('Now I can do the rest of the code') //Do the actual code here callback(null, 'success') } 

根据pspi的回答和一些更多的研究,我认为更正确的解决scheme是这样的:

 var AWS = require('aws-sdk') var s3 = new AWS.S3(); var params = { Bucket: 'bucket-name', Key: 'file-name' }; var fileLoaded = false; exports.handler = (event, context, callback) => { if(!fileLoaded){ s3.getObject(params, function (err, data) { if (err) console.log(err, err.stack); else { fileLoaded = true; doSomething(event, context, callback) } }); } else { doSomething(event, context, callback) } }; function doSomething(event, context, callback){ //Do the actual work here callback(null, "success") //Then end } 

这似乎给出了只从S3加载文件的预期结果,但不允许在没有加载完成的情况下执行代码。 如果S3被多次调用冷态,它将允许多个S3请求,但这不太可能,并且比每次调用该函数都要好。

嘿嘿,asynchronous代码和模块很快就失去控制,不是吗?

只要asynchronouss3.getObject()调用准备就绪,您就想调用callback函数。 然后将正确的位置放在s3.getObject()callback中。 像这样,除去另一个绒毛

 var AWS = require('aws-sdk') var s3 = new AWS.S3(); var params = { Bucket: 'bucket-name', Key: 'file-name' }; exports.handler = (event, context, callback) => { s3.getObject(params, function (err, data) { if (err) console.log(err, err.stack); else { callback(null, 'success') // do after we have completed s3.getObject() } }); }; 

如果可以多次调用exports.handler,则应该稍微调整代码(caching结果)。 而且我似乎没有认识到实际的文件数据在哪里传递,但是你得到了它的要点。

在这里,你有一个清晰的版本承诺:

 var AWS = require('aws-sdk') var s3 = new AWS.S3(); var params = { Bucket: 'bucket-name', Key: 'file-name' }; var fileData = null; exports.handler = (event, context, callback) => { if(!fileData) s3.getObject(params).promise().then(data) => { fileData = data; doSomething(event, context, callback); }).catch((err) => { callback.done(err); }); else doSomething(event, context, callback); }; function doSomething(event, context, callback){ // Do the actual work here // you can use fileData variable now to use your downloaded file!! callback(null, "success") // Then end } 

我喜欢预先加载资源并使用承诺来限制stream量。 一个“冷”容器必须得到文件,但一个温暖的容器已经拥有它。 在模块设置中加载它,在lambda实际调用你的端点的时候给它一个开始的小小的位。

 var AWS = require('aws-sdk') var s3 = new AWS.S3(); var fileDataPromise = getFileDataPromise(); exports.handler = (event, context, callback) => { fileDataPromise.then((fileData) => { doSomething(event, context, callback, fileData); }) }; function getFileDataPromise() { var params = { Bucket: 'bucket-name', Key: 'file-name' }; return new Promise((resolve, reject) => { s3.getObject(params, (err, data) => { if (err) console.log(err, err.stack); else { resolve(data) } }) }) } function doSomething(event, context, callback, fileData) { // Do the actual work here callback(null, "success") }