Как загрузить файл с URL-адреса, используя AWS лямбда с кодом node.js - PullRequest
1 голос
/ 14 июля 2020

Мне трудно написать код для моей лямбда-функции. Эта функция должна загружать файлы в каталог / tmp, но вместо этого создает файлы с нулевым размером. Результат выглядит так:

2020-07-13T21: 28: 09.694-05: 00 2020-07-14T02: 28: 09.681Z a914d6fa-0b29-4c66-8cc5-95095575be7b INFO / tmp / 7za123. zip

2020-07-13T21: 28: 09.994-05: 00 2020-07-14T02: 28: 09.975Z a914d6fa-0b29-4c66-8cc5-95095575be7b ИНФОРМАЦИЯ /tmp/7za321.zip

2020-07-13T21: 28: 10.014-05: 00 2020-07-14T02: 28: 09.995Z a914d6fa-0b29-4c66-8cc5-95095575be7b ИНФОРМАЦИЯ /tmp/7za920.zip

2020-07 -13T21: 28: 10.016-05: 00 2020-07-14T02: 28: 10.016Z a914d6fa-0b29-4c66-8cc5-95095575be7b ИНФОРМАЦИЯ 0

2020-07-13T21: 28: 10.017-05: 00 2020-07-14T02: 28: 10.017Z a914d6fa-0b29-4c66-8cc5-95095575be7b ИНФОРМАЦИЯ 0

2020-07-13T21: 28: 10.017-05: 00 2020-07-14T02: 28: 10.017Z a914d6fa-0b29-4c66-8cc5-95095575be7b ИНФОРМАЦИЯ 0

Не могли бы вы помочь мне исправить это?

      var AWS = require('aws-sdk')
      var response = require('cfn-response')
      var fs = require('fs')
      var path = require('path')
      var https = require('https')
      var urlmod = require('url')
      var {promisify} = require('util')
      var stream = require('stream')
      var finished = promisify(stream.finished)
      var s3 = new AWS.S3()

      function getFilesizeInBytes(filename) {
        var stats = fs.statSync(filename)
        var fileSizeInBytes = stats["size"]
        return fileSizeInBytes
      }

      download = async function (filename, url) {
        console.log(filename)
        file = fs.createWriteStream(filename)
        request = https.get(url, function(resp) {
          resp.pipe(file)
        })
        await finished(file)
      }


      exports.lambda_handler = (event, context, callback) => {
        var s3buketname = event.ResourceProperties.S3BucketName
        var urls = event.ResourceProperties.Urls

        for(let url of urls) {
          filename = '/tmp/' + path.basename(urlmod.parse(url, true).pathname)
          download(filename, url)
        }

        for(let url of urls) {
          filename = '/tmp/' + path.basename(urlmod.parse(url, true).pathname)
          console.log(getFilesizeInBytes(filename))
        }

        responseData = {Result: "good"}
        response.send(event, context, response.SUCCESS, responseData)
      }

1 Ответ

1 голос
/ 14 июля 2020

Вы должны подождать, пока поток с возможностью записи запустит событие 'fini sh' .

Что происходит, так это то, что процесс завершается почти сразу, потому что он никогда не ждет request.pipe (файл), который должен быть фактически выполнен.

Одна стратегия, которая включает в себя 2 дополнительных шага:

  1. использовать async / awaits в циклах (также известную как асинхронная итерация ECMAScript 2018) , что-то вроде:
  for await (...) {
    await download(...)
  }
для каждого URL-адреса, дождитесь, пока записываемый поток выдаст событие 'fini sh', что также можно сделать с помощью async / await, используя streams.finished () в сочетании с util.promisify ()
const {promisify} = require('util')
const stream = require('stream')
const finished = promisify(stream.finished)
await finished(aStream)

Обратите внимание, что это очень простой c подход, который приведет к еще большей путанице в коде, и, вероятно, каждая загрузка будет выполняться последовательно, как и каждые l oop будет ждать финиша трубы sh. Вдобавок ко всему, обработка ошибок для отдельного канала будет беспорядком и многими другими проблемами. Это будет работать, но не будет хорошо.

Гораздо более понятный подход придет в изучении того, как писать asyn c каналы с Highland. js. Это будет нелегко для новичков с этим инструментом, так как это сразу потребует запуска asyn кода c с sequence и, вероятно, также fork/merge каналов. Если вам интересно, я могу подробнее рассказать об этом.

...