【问题标题】:Objects Overwritten Despite Different Keys尽管有不同的键,但对象被覆盖
【发布时间】:2018-02-01 11:16:19
【问题描述】:

希望这里有人可以为我阐明这种情况 - 也许我错过了一些简单的东西。

我有一个流程设置,我的应用从 S3 存储桶中获取预签名的 URL,以上传一张或多张图片。上传图片后,会触发在 SDK 之上编写的 Lambda 函数。这个 lambda 应该将图像调整为 3 种不同的大小,并为它们分配键/将它们放入“文件夹”中,如下所示:photos/000/123/456/medium/image.jpg, photos/000/123/456/large/ image.jpg,照片/000/123/456/original/image.jpg.

不幸的是,每次迭代都会覆盖前一个对象,因此 photos/000/123/456/ 最终只包含 original/image.jpg。我的印象是,所有三个,因为它们是不同的键,将被保存而不是相互覆盖。好像不是这样的?下面的代码示例(请注意,最初图像是通过循环放置到它们的目标存储桶中的;在分解代码的过程中,它变得有些混乱,但它可以工作并且结果在有或没有循环的情况下是相同的):

// dependencies
var async = require('async');
var path = require('path');
var AWS = require('aws-sdk');
var gm = require('gm')
            .subClass({ imageMagick: true }); // Enable ImageMagick integration.
var util = require('util');

var max_width  = 20;
var max_height = 20;

// get reference to S3 client
var s3 = new AWS.S3();

exports.handler = function(event, context) {
  // Read options from the event.
  console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
  var srcBucket = event.Records[0].s3.bucket.name;
  // Object key may have spaces or unicode non-ASCII characters.
    var srcKey    =
    decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
  var dstBucket = srcBucket;
  var dstKey    = srcKey.replace('originals', 'assets');
  var extension = path.extname(dstKey);
  var filename  = path.basename(dstKey, extension);
  var directory = path.dirname(dstKey);
  // dstKey = directory + '/' + filename + extension;
  // var sub_folders = ['original', 'large', 'medium', 'thumb']


    //  LARGE image from S3, transform, and upload to a different S3 bucket.
    dstKey = directory + '/' + 'large' + '/' + filename + extension;
    max_width  = 600;
    max_height = 600;
    async.waterfall([
      function download(next) {
        // Download the image from S3 into a buffer.
        s3.getObject({
            Bucket: srcBucket,
            Key: srcKey
          },
          next);
        },
      function transform(response, next) {
        gm(response.Body).size(function(err, size) {
          // Infer the scaling factor to avoid stretching the image unnaturally.
          var scalingFactor = Math.min(
            max_width / size.width,
            max_height / size.height
          );
          var width  = scalingFactor * size.width;
          var height = scalingFactor * size.height;
          // var height = scalingFactor * size.height;
          // Transform the image buffer in memory.
          this.resize(width, height)
            .toBuffer(null, function(err, buffer) {
              if (err) {
                next(err);
              } else {
                next(null, response.ContentType, buffer);
              }
            });
        });
      },
      function upload(contentType, data, next) {
        // Stream the transformed image to a different S3 bucket.
        s3.putObject({
            Bucket: dstBucket,
            Key: dstKey,
            Body: data,
            ContentType: contentType
          },
          next);
        }
      ], function (err) {
        if (err) {
          console.error(
            'Unable to resize ' + srcBucket + '/' + srcKey +
            ' and upload to ' + dstBucket + '/' + dstKey +
            ' due to an error: ' + err
          );
        } else {
          console.log(
            'Successfully resized ' + srcBucket + '/' + srcKey +
            ' and uploaded to ' + dstBucket + '/' + dstKey
          );
        }

        context.done();
      }
    );


    // MEDIUM download the image from S3, transform, and upload to a different S3 bucket.
    dstKey = directory + '/' + 'medium' + '/' + filename + extension;
    max_width  = 600;
    max_height = 600;
    async.waterfall([
      function download(next) {
        // Download the image from S3 into a buffer.
        s3.getObject({
            Bucket: srcBucket,
            Key: srcKey
          },
          next);
        },
      function transform(response, next) {
        gm(response.Body).size(function(err, size) {
          // Infer the scaling factor to avoid stretching the image unnaturally.
          var scalingFactor = Math.min(
            max_width / size.width,
            max_height / size.height
          );
          var width  = scalingFactor * size.width;
          var height = scalingFactor * size.height;
          // var height = scalingFactor * size.height;
          // Transform the image buffer in memory.
          this.resize(width, height)
            .toBuffer(null, function(err, buffer) {
              if (err) {
                next(err);
              } else {
                next(null, response.ContentType, buffer);
              }
            });
        });
      },
      function upload(contentType, data, next) {
        // Stream the transformed image to a different S3 bucket.
        s3.putObject({
            Bucket: dstBucket,
            Key: dstKey,
            Body: data,
            ContentType: contentType
          },
          next);
        },

      function transform(response, next) {
        gm(response.Body).size(function(err, size) {
          // Infer the scaling factor to avoid stretching the image unnaturally.
          var scalingFactor = Math.min(
            330 / size.width,
            330 / size.height
          );
          var width  = scalingFactor * size.width;
          var height = scalingFactor * size.height;
          // var height = scalingFactor * size.height;
          // Transform the image buffer in memory.
          this.resize(width, height)
            .toBuffer(null, function(err, buffer) {
              if (err) {
                next(err);
              } else {
                next(null, response.ContentType, buffer);
              }
            });
        });
      },
      function upload(contentType, data, next) {
        // Stream the transformed image to a different S3 bucket.
        s3.putObject({
            Bucket: dstBucket,
            Key: directory + '/' + 'medium' + '/' + filename + extension,
            Body: data,
            ContentType: contentType
          },
          next);
        }
      ], function (err) {
        if (err) {
          console.error(
            'Unable to resize ' + srcBucket + '/' + srcKey +
            ' and upload to ' + dstBucket + '/' + dstKey +
            ' due to an error: ' + err
          );
        } else {
          console.log(
            'Successfully resized ' + srcBucket + '/' + srcKey +
            ' and uploaded to ' + dstBucket + '/' + dstKey
          );
        }

        context.done();
      }
    );    


};

【问题讨论】:

    标签: amazon-s3 aws-lambda


    【解决方案1】:

    简而言之,您的代码实际上并不是按照您的意图编写的。

    async.waterfall( ... ); 不会阻塞周围的程序流。它几乎立即返回——我不确定这是否发生在 first 嵌套函数开始之后或之前,但它是这两者之一——并且精确的时间在当前的讨论,因为无论哪种方式,它都会很快返回并且执行会继续它下面的任何内容。

    因此,您将多次覆盖内存中 dstKey 和其他变量的值您的瀑布嵌套函数实际上开始使用变量的值......他们会看到当前值。 dstKey 的值在任何调整大小操作完成之前位于 final 分配的值,因此,正在覆盖对象,因为你总是使用 dstKey 的最后一个值。

    这些瀑布都在不协调地并行执行。这就是异步函数的运作方式。他们不能阻止执行——这也会阻止事件循环。

    记录各种函数内的变量值(以及您所在位置的上下文,例如在调用 s3 上传函数之前),您应该能够看到这一点。

    【讨论】:

    • 非常正确。这就是以 JS 术语以外的任何方式接近 JS 的结果。 :) 感谢您的反馈,谢谢。
    猜你喜欢
    • 2023-01-25
    • 1970-01-01
    • 2020-07-24
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多