【问题标题】:Can't download files from S3 using nodeJS: few files don't finish无法使用 nodeJS 从 S3 下载文件:一些文件没有完成
【发布时间】:2017-03-08 03:46:17
【问题描述】:

这让我发疯了。

我需要我的服务器从 S3 下载 100 个相对较小的文件文件(最大 2 Mb)。

它始终适用于约 95% 的文件,但它会阻止最后 6-8 个文件。 resolvereject 回调永远不会被调用...

我尝试并行下载文件...

  • 有人遇到过这种情况吗?
  • 会不会是丢包导致流没有关闭?
  • 是否有最大并发下载数?

这是代码,从技术上讲,它适用于 95% 的情况:

  let singleGetFromS3 = (bucket, fileName) => {
    return new Promise((resolve, reject) => {
      let extension = getFileNameExtension(fileName);
      fs.stat(`./${fileName}`, (err, stat) => {
        if (err === null) {
          console.log(`${fileName} exists locally`);
          resolve(fileName);
        } else if(err.code === 'ENOENT') {
          let params = {Bucket: bucket, Key: fileName};
          let file = require('fs').createWriteStream(`./tmp-${fileName}`);
          s3.getObject(params).createReadStream()
            .on('error', (error) => { return reject(error); })
            .on('end', () => {
              fs.rename(`./tmp-${fileName}`, `./${fileName}`, reject);
              return resolve(fileName);
            })
            .pipe(file);
        } else {
          reject(err);
        }
      });
    });
  };

使用:

"aws-sdk": "^2.23.0",
node --version
v4.5.0

【问题讨论】:

    标签: node.js amazon-s3


    【解决方案1】:

    看起来您正在侦听错误的事件以了解何时解决。您不想在从 S3 的 Readable 读取所有字节后解析,您希望在 file 完成写入后解析。

    let singleGetFromS3 = (bucket, fileName) => {
        return new Promise((resolve, reject) => {
          let extension = getFileNameExtension(fileName);
          fs.stat(`./${fileName}`, (err, stat) => {
            if (err === null) {
              console.log(`${fileName} exists locally`);
              resolve(fileName);
            } else if(err.code === 'ENOENT') {
              let params = {Bucket: bucket, Key: fileName};
              let file = require('fs').createWriteStream(`./tmp-${fileName}`);    
    
              // Listen for the file to be done writing, then resolve
              file.on('finish', () => {
                  fs.rename(`./tmp-${fileName}`, `./${fileName}`, reject);
                  return resolve(fileName);
                })
    
              s3.getObject(params).createReadStream()
                .on('error', (error) => { return reject(error); })
                .pipe(file);
            } else {
              reject(err);
            }
          });
        });
      };
    

    【讨论】:

    • 谢谢。我考虑过这一点,但没有想到 writeStream 自行关闭的原因。但显然它有效,虽然我还有 5~6 个文件没有完成.... :( :(
    • 顺便说一句,我很惊讶地发现 S3 中这种微不足道的操作在 nodeJS 中是这样的痛苦......
    • @AugustinRiedinger 如果你想简化这一点,我会首先不在同一个函数中使用回调、事件/流和承诺。你应该使用 bluebird.js 到 promisify 你的 fs 所以你不需要 fs.stat() 回调。我还编辑了答案,不要使用我最初放置的'close' 事件,而是使用'finish'
    • @AugustinRiedinger 让我总结一下要点
    猜你喜欢
    • 2021-06-26
    • 1970-01-01
    • 2017-01-13
    • 2011-12-27
    • 2018-01-09
    • 2021-12-18
    • 2019-09-06
    • 1970-01-01
    • 2022-11-17
    相关资源
    最近更新 更多