【问题标题】:Downloading multiple files from aws to Node js server将多个文件从 aws 下载到 Node js 服务器
【发布时间】:2019-06-27 00:50:06
【问题描述】:

我需要从 aws s3 下载大量文件(比如 100k,每个文件大小 0.2 - 1 MB)到节点 js 服务器。我使用的代码是

app.get('/api/download-all', function(req, res) {
   res.json({status: 'download initiated'})
   downloadFromS3(getDocs());    
});

下载音频的功能是

function downloadFromS3(docs){
docs.forEach((doc, fileIndex)=>{
    var s3FilePath = doc.wav
    var fileName = s3FilePath.split('/').pop();
    var s3Params = {Bucket: 'zzzzz', Key: s3FilePath};
    var file = fs.createWriteStream(dir + '/' + fileName);
    console.log(downloadSession);
    s3.getObject(s3Params)
        .on('httpData', function (chunk) {
            console.log("file writing happening", fileName);
            file.write(chunk);
        })
        .send();
}); }

这里下载函数触发 S3.getObject 调用的次数与要下载的文件数量一样多。它不等待文件的状态。在让文件下载之前,它几乎已经制作了大约 100k(在我的情况下)s3.getObject。这是正确的方法还是我应该等待一个文件下载并在此之后调用 s3 调用。什么是正确的方法。

2) 我在使用此代码时还面临另一个问题。一旦我从 UI 进行下载 api 调用,服务器就会忙于下载。它没有从 UI 返回任何请求。所有请求都挂起。有没有办法在后台下载。我经历了一些方法,比如分叉一个子进程或一个网络工作者来处理这个问题。我不确定使用哪一个。处理这个问题的最佳方法是什么。

【问题讨论】:

  • 像这样下载这么多单个文件有点不寻常。为什么要下载 100k 个文件?想知道是否有机会重新思考您的设计。

标签: javascript node.js amazon-web-services amazon-s3 download


【解决方案1】:

我建议采用中间方法。并行启动 10 万次下载确实不是一个好主意。但同样,等待每次下载完全完成也不会利用您的全部带宽。我建议一个“汇集”工作的解决方案 - 例如,您创建一个承诺池,每个承诺一次可以下载一个文件,一旦完成就开始下一个文件。

我一直在使用这样的函数:

Promise.pool = function pool(funcs, inParallel, progressCallback) {
  const promises = [];
  const results = [];
  function getNext() {
    if (funcs.length) {
      return funcs.pop()()
      .catch(() => {})
      .then((res) => {
        results.push(res);
        if (progressCallback) {
          progressCallback(results);
        }
        return getNext();
      });
    }
  }
  for (let i = 0; i < Math.min(inParallel, funcs.length); i++) {
    promises.push(getNext());
  }
  return Promise.all(promises)
  .then(() => results);
};

然后你会定义一个函数数组,每个函数下载一个文件并返回一个在完成时解析的承诺:

const funcs = docs.map((doc) => {
   return () => {
    return new Promise((resolve) => {
     var s3FilePath = doc.wav
     var fileName = s3FilePath.split('/').pop();
     var s3Params = {Bucket: 'zzzzz', Key: s3FilePath};
     var file = fs.createWriteStream(dir + '/' + fileName);
     console.log(downloadSession);
     s3.getObject(s3Params)
        .on('httpData', function (chunk) {
            console.log("file writing happening", fileName);
            file.write(chunk);
        })
        .on("end", () => resolve())
        .send();
    });
   }
});

最后,你会这样使用它:

const inParallel = 32;
function callback(partialResults) {
 //console log, whatever
}
Promise.pool(funcs, inParallel, callback)
.then(() => console.log("all done!"));

【讨论】:

  • 在 inParallel 计数之后它没有继续,我有 2 个 inParallel 并且在 2 个之后它只是停止并且它也没有打印所有完成和部分结果控制台。你能帮我吗
猜你喜欢
  • 2022-10-16
  • 2021-02-20
  • 1970-01-01
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
相关资源
最近更新 更多