在主程序

时间:2016-08-12 10:42:06

标签: node.js amazon-web-services asynchronous amazon-s3 aws-lambda

我正在编写一个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')
}

4 个答案:

答案 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")
}