我正在编写一个lambda函数,需要加载存储在S3中的密钥。它不会经常改变,所以我不想在每次调用lambda函数时都抓住它,所以我想在容器旋转时加载它一次,然后在lambda容器的生命周期内保留该值。 / p>
但是,由于异步方法getObject,这导致了一个问题,因为在运行main module.export代码时可能没有加载该文件(特别是如果这是第一次运行一段时间并且正在创建容器)
我已经使用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')
}
答案 0 :(得分:3)
根据pspi的回答和更多研究,我认为更正确的解决方案是:
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请求,但这不太可能,并且仍然比每次调用函数都要好。
答案 1 :(得分:1)
嘿嘿,异步代码和模块很快失控,不是吗。
您希望在异步s3.getObject()调用准备就绪后立即调用您的回调。然后,正确的位置是将工作回调放在s3.getObject()回调中。像这样,去除其他绒毛
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,则应该调整代码(缓存结果)。我似乎没有认识到传递实际文件数据的位置,但你得到了它的要点。
答案 2 :(得分:1)
这里你有一个更清洁的版本,承诺:
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
}
答案 3 :(得分:0)
我喜欢预加载资源并使用promise来控制流。 A"冷"容器必须得到文件,但一个温暖的容器已经拥有它。在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")
}