【发布时间】:2019-06-01 15:41:20
【问题描述】:
我正在使用 here 找到的 Amazon S3 教程修改 AWS Lambda,以便它能够简单地--
- 读取已驻留在该存储桶中的 JSON 文件(内容索引),
- 使用新创建的密钥(该存储桶中触发此 Lambda 的新“文件夹”)对其进行更新,
- 然后将更新的 JSON 文件保存(放置)回去。
澄清: 只有在其中创建文件夹对象时,存储桶才应触发 Lambda 函数。内容索引 (index.json) 已驻留在存储桶中。因此,bucket 将包含文件夹(例如,{folder-1、folder-2、folder-n})和 index.json。每次添加新文件夹时,都会将其添加到 JSON 数组中。
具体来说,在我的例子中,我有一个根(目标)存储桶,其中包含由 Elemental MediaConvert 创建的一系列文件夹。每个文件夹代表一个新视频;每个文件夹中都有可以提供给不同设备的不同格式。回到根级别,我有 index.json,它是这些视频文件夹的数组;它是内容索引。现在,我可以修改作为 MediaConvert 流一部分的 Lambda。但我会在其他时间考虑。在这里,我只想在每次 MediaConvert 写入一个新的视频文件夹时触发一个新的 S3 Lambda……这只是一些随机的 GUID。
我正在学习 Node JS,这是我第一次使用一些结构并调用你在这里看到的。 (我至少知道这种形式比使用回调更清晰。)
由于将其作为 Lambda 函数进行测试会很棘手(对我来说!),有人会指出任何明显的错误吗??
另外,有人会告诉我如何使用 Amazon S3 事件数据手动测试这个 Lambda 函数(在配置实际存储桶以发布所需事件之前)吗?我想我需要 event.json 来指定新创建的文件夹的名称,这样它就可以添加到我的 index.json 中,它也位于同一个存储桶中。
这是我的代码:
// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var util = require('util');
// constants
//const DEST_FOLDER = 'my-triggering-bucket';
const CONTENT_INDEX_FILENAME = 'index.json';
// get reference to S3 client
var s3 = new AWS.S3();
exports.handler = function(event, context, callback) {
// Read options from the event.
// Need the new folder (key) that's been added to the bucket...
console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
// I assume this is the triggering bucket...
var triggerBucket = event.Records[0].s3.bucket.name;
// And I assume this is the folder that was added and caused the trigger
var newKey = decodeURIComponent(event.Records[0].s3.object.key);
const indexKey = CONTENT_INDEX_FILENAME;
// Get the content index and add the newly created dir to it
async.waterfall([
function download(next) {
// Download the content index from S3 into a buffer.
s3.getObject({
Bucket: triggerBucket,
Key: indexKey
},
next);
},
function update(response, next) {
// Update the content index with the new dir that was added
console.log('UPDATE...');
var obj = JSON.parse(response);
obj.push(newKey);
var jsonStr = JSON.stringify(obj);
next(null, jsonStr.ContentType, jsonStr);
},
function upload(contentType, data, next) {
// Stream the updated content index back
s3.putObject({
Bucket: triggerBucket,
Key: indexKey,
Body: data,
ContentType: contentType
},
next);
}
], function (err) {
if (err) {
console.error('error: ' + err);
} else {
console.log('Success);
}
callback(null, "message");
}
);
};
更新
我已经放弃了这种方法,转而通过另一种方式更新内容索引,这种方式不会冒着我的 Lambda 执行失控的风险。我亲身发现,当一个人的设计不提供可靠的事件通知过滤器时,尝试在存储桶中触发特定的 createObject 事件并不是一个好主意。 (我无法过滤简单的/ 的后缀。)此外,我期待单个文件夹键对象创建事件来触发我的 Lambda,但实际上其他文件夹和键在 内部创建新的根级文件夹最终也触发了我的 Lambda。因此,这让我进入了视频转换工作流程,以修改通知工作流程成功完成的 Lambda,从而更新我的内容索引。
【问题讨论】:
-
注意#1:使用两个存储桶会更安全,否则如果此 Lambda 函数正在写入触发它的同一个存储桶,以及新的或覆盖的对象(由 Lambda 函数创建)还会触发 Lambda 函数,您有一个无限循环的 Lambda 调用和存储桶
PUT操作,如果不及时检测到,可能会花费真正的美元。至少确保新对象不会触发包含自身。 -
注意 #2:此代码将错误放置(偶尔省略)文件以包含在索引中,因为有一个隐含的假设,即当并行上传发生时 Lambda 函数不会同时运行 - 它会 -并且 s3.getObject 始终获取已被覆盖的(索引)对象的最新副本 - 它可能不会。这是不能保证的。快速读取后的覆盖可能会返回旧对象或新对象。它总是会返回一个完整的对象,但 S3 只保证覆盖的最终一致性。
-
感谢您的提醒。不,我没有考虑过这两种情况..但我想当我接近时第一个会突然出现在我身上!这很容易防止,因为触发操作将是一个新的“文件夹”出现在存储桶中......而不是更新的 JSON 对象。我需要考虑@athar-kahn 在下面的回复,因为他似乎表示创建新文件夹不会触发我的 Lambda。至于第 2 点,在这个阶段不可能有并发的可能性.. 但这是需要牢记的。谢谢!
标签: javascript node.js amazon-web-services amazon-s3 aws-lambda