AWS nodejs microservice:在S3存储桶中的文件发生更改时迭代调用服务

我使用nodejs在lambda上创build了一个微服务,以在S3存储桶中生成我的图像的缩略图。 但是,在将新映像上传到S3存储桶后,没有被触发。 我将触发器事件types设置为创build的S3对象。 而且我还将testing事件configuration为: "eventName": "ObjectCreated:*" ,这意味着在桶中创build/更改某些文件时,应该触发testing事件并调用此lambda函数。 我也在桶侧设置了相同的通知configuration。 它在我第一次从这个例子创build这个lambda函数的时候起作用: 创build一个部署包

该function只适用于确切的文件“HappyFace.jpg”,但失败的所有其他图像。 有时我得到“拒绝访问”错误。 我使用下面的代码:

 // dependencies var async = require('async'); var AWS = require('aws-sdk'); var gm = require('gm') .subClass({ imageMagick: true }); // Enable ImageMagick integration. var util = require('util'); var utils = require('utils'); // constants var MAX_WIDTH = 100; var MAX_HEIGHT = 100; // get reference to S3 client var s3 = new AWS.S3(); exports.handler = function(event, context, callback) { // 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 + "-resized"; var dstKey = "resized-" + srcKey; // Sanity check: validate that source and destination are different buckets. if (srcBucket == dstBucket) { callback("Source and destination buckets are the same."); return; } // Infer the image type. var typeMatch = srcKey.match(/\.([^.]*)$/); if (!typeMatch) { callback("Could not determine the image type."); return; } var imageType = typeMatch[1]; if (imageType != "jpg" && imageType != "png") { callback('Unsupported image type: ${imageType}'); return; } // Download the image from S3, transform, and upload to a different S3 bucket. 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; // Transform the image buffer in memory. this.resize(width, height) .toBuffer(imageType, 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 ); } callback(null, "message"); } ); }; 

并在下载之前configuration了types匹配。 我试图使用s3.ListObjects,但是对我来说没有任何意义。 由于lambda可以被上传事件触发,所以每次我上传一个新的图像时都应该调用该图像,所以我不想每次都列出这些对象。

更新:

获取pipe理员权限后,我摆脱了访问被拒绝的问题。 它激励我检查我安装的节点包。 我们可以通过这种方式来排除故障。 但是,我从npm安装'utils'后,我无法调用现有文件的function。

access denied错误可能不是IAM / S3桶/ lambda权限问题。 如果您的服务无法在您的S3存储桶中find给定的密钥,则它也会向请求者返回access denied错误。 因为返回NoSuchKey会泄漏有关所请求密钥的不存在的信息。 有关参考,请检查此链接: 访问被拒绝错误的原因

至于如何迭代调用lambda函数,你绝对不需要在你的代码中调用s3.ListObject() ,因为这会降低你的性能。 但是,此链接可能会帮助您定制您的function: 使用适用于Node.js的AWS开发工具包列出大型S3存储桶 。 在这个问题给出的例子中,注意到他们包括util包:

 var util = require('util'); 

但是他们如何安装npm是通过这个命令行:

 npm install async gm 

如果你想让这个函数被迭代地调用,你也可以通过npm install utils来通过npm来安装“utils”。 当它通过你的桶迭代工作时,你可能会因为某些文件而access denied错误,因为你可能没有在你的事件中configuration密钥。 你可以忽略这一点。

更新

我也设法把原始图像和缩略图放在同一个桶里,你需要做的是两件事:

  1. 通过检查前缀或后缀来跳过缩略图。
  2. 设置超时间隔。 由于我们使用的是“asynchronous”,因此我们不需要为瀑布函数设置setTimeout,我们可以将它设置在瀑布之外,但在处理程序内部。 您也可以在GUI中设置超时和时间安排事件。

重要更新:

不幸的是,我原来的解决scheme并不完美。 我有另一个更安全的解决scheme。 有三个步骤:

  1. 将您的S3存储桶configuration为SQS队列。
  2. 监听asynchronous循环(或setInterval)中的每个传入消息。
  3. 在每个SQS消息的asynchronous循环中执行缩略图function。

代码将大致如下所示:

 s3.listObjects({Bucket:"myBucket",Delimiter:"",Prefix:""}, function (err, data) { if (err) throw err; thumbnail(event, function(err){}) }); setInterval(function() { console.log("Pause"); sqs.receiveMessage(receiveParams, function(err,data){ console.log("Calling"); if (err) { console.log(err); } else { if (data.Messages != null) { thumbnail(data.Messages[0].Body, function(err){ if (err) { console.log(err); } }); } } }); }, 1000);