【问题标题】:Load S3 file in lambda before main procedure在主过程之前在 lambda 中加载 S3 文件
【发布时间】:2016-12-19 08:28:25
【问题描述】:

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

但是,由于异步方法 getObject,这会导致一个问题,因为在运行主 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')
}

【问题讨论】:

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


    【解决方案1】:

    根据 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 的多个请求,但这不太可能并且仍然比每次调用该函数时更好。

    【讨论】:

      【解决方案2】:

      嘿嘿,异步代码和模块很快就会失控,不是吗。

      您希望在异步 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 可以被多次调用,那么代码应该被进一步调整(缓存结果)。而且我似乎不知道实际文件数据是在哪里传递的,但你明白了它的要点。

      【讨论】:

      • 感谢您的回复,但这意味着每次调用此 lambda 时,它都会去 S3 再次抓取文件 - 这是不必要的。我想我需要实现你和我的解决方案的组合并缓存结果,这样它就不会每次都命中 S3。
      【解决方案3】:

      这里你有一个带有承诺的更简洁的版本:

      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
      }
      

      【讨论】:

        【解决方案4】:

        我喜欢预加载资源并使用承诺来控制流程。一个“冷”容器必须去获取文件,但一个温暖的容器已经有了它。在 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")
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-01
          • 2014-12-09
          • 2018-12-01
          • 2019-06-14
          • 1970-01-01
          • 2018-08-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多