在 AWS Lambda 中读取事件流时出现问题 Nodejs 代码根据需要在本地工作,但不在 AWS Lambda 中

问题描述

工作流程如下:

获取 https 链接 --> 写入文件系统 --> 从文件系统读取 --> 获取 sha256 哈希值。

它在运行节点 10.15.3 的本地机器上运行良好,但是当我在 AWS 上启动 lambda 函数时,输出为空。 可读流可能存在一些问题。这是代码。您可以直接在本地计算机上运行它。它将根据需要输出 sha256 哈希值。如果您希望在 AWS Lambda 上运行,请按标记注释/取消注释。

//Reference: https://stackoverflow.com/questions/11944932/how-to-download-a-file-with-node-js-without-using-third-party-libraries



var https = require('https');
var fs = require('fs');
var crypto = require('crypto')
const url = "https://upload.wikimedia.org/wikipedia/commons/a/a8/TEIDE.JPG"
const dest = "/tmp/doc";
let hexData;


async function writeit(){
  var file = fs.createWriteStream(dest);
  return new Promise((resolve,reject) => {
    var responseSent = false;
    https.get(url,response => {
      response.pipe(file);
      file.on('finish',() =>{
        file.close(() => {
          if(responseSent)  return;
          responseSent = true;
          resolve();
        });
    });

}).on('error',err => {
        if(responseSent)  return;
        responseSent = true;
        reject(err);
    });
  });

}



const readit = async () => {

await writeit();

var readandhex = fs.createReadStream(dest).pipe(crypto.createHash('sha256').setEncoding('hex'))
try {
  readandhex.on('finish',function () {       //MAY BE PROBLEM IS HERE.
    console.log(this.read())
    fs.unlink(dest,() => {});
   })
}
catch (err) {
    console.log(err);
    return err;
}
}



const handler = async() =>{                  //Comment this line to run the code on AWS Lambda
//exports.handler = async (event) => {       //UNComment this line to run the code on AWS Lambda
    try {
        hexData = readit();
    }
    catch (err) {
        console.log(err);
        return err;
    }
    return hexData;
};



handler()                                   //Comment this line to run the code on AWS Lambda

解决方法

您可能需要检查多项内容。

  1. 由于您访问的 URL 是公开的,因此请确保您的 lambda 位于 VPC 之外,或者您的 VPC 具有连接互联网访问权限的 NAT 网关。

  2. /tmp 是 lambda 的有效临时目录,但您可能需要在使用它之前在 doc 内创建 /tmp 文件夹。

您可以查看 cloud-watch 日志,了解有关启用后会发生什么的更多信息。

,

我以前见过 local 和 lambda 之间的这种行为差异。

所有异步函数都返回承诺。必须等待异步函数。在不等待的情况下调用异步函数意味着继续执行到下一行,并且可能在调用函数之外执行。

所以你的代码:

exports.handler = async (event) => {
    try {
        hexData = readit();
    }
    catch (err) {
        console.log(err);
        return err;
    }
    return hexData;
};

readit() 被定义为 const readit = async () => { ... }。但是您的处理程序不会等待它。因此,hexData = readit(); 将未解决的承诺分配给 hexData,将其返回,然后处理程序退出,Lambda “完成”,而 readit() 的代码尚未执行。

简单的解决方法是等待异步函数:hexData = await readit();。它在 node 本地工作的原因是因为 node 进程会在退出之前等待 promise 解决,即使处理程序函数已经返回。但是由于 Lambda 在处理程序返回后立即“返回”,因此未解决的承诺仍然未解决。 (顺便说一句,writeit 函数不需要被标记为异步,因为它不等待任何东西,并且已经返回了一个承诺。)

话虽如此,我不太了解承诺,而且我对事件几乎一无所知。所以还有其他事情会为我引发警告标志,但我不确定它们,也许它们完全没问题,但我会在这里提出以防万一:

file.on('finish'readandhex.on('finish'。这些都是事件,我相信它们是非阻塞的,那么为什么处理程序和 lambda 会等待它们呢?

在第一种情况下,它在一个 promise 中,并且 resolve() 在事件函数中被调用,所以这可能没问题(正如我所说,我对这两个主题不太了解,所以我不确定) - 重要的是代码必须在那个点阻塞,直到承诺得到解决。如果代码可以继续执行(即从 writeit() 返回),直到引发 finish 事件,则它不会工作。

第二种情况几乎肯定会有问题,因为它只是说 if x 事件被引发,then do y。没有等待的承诺,所以没有什么可以阻止代码,所以它会很高兴地继续到 readit() 函数的末尾,然后是处理程序和 lambda。同样,这是基于事件是非阻塞的假设(从某种意义上说,您要在某个事件上执行某些代码的声明,不会在该点等待引发该事件)。