Событие AWS S3 Lambda - получить, обновить, затем поместить файл JSON из той же корзины - PullRequest
0 голосов
/ 07 января 2019

Я изменяю AWS Lambda с помощью учебника Amazon S3, найденного здесь , чтобы он просто -

  • читать файл JSON (индекс содержимого), уже находящийся в этом сегменте,
  • обновить его с помощью только что созданного ключа (новая «папка» в той корзине, которая запустила эту лямбду),
  • и затем сохраните (поместите) обновленный файл JSON обратно.

РАЗЪЯСНЕНИЯ: Контейнер должен запускать функцию Lambda только тогда, когда в ней создается объект папки. Индекс содержимого (index.json) уже находится в корзине. Таким образом, в bucket будут папки (например, {folder-1, folder-2, folder-n}) и index.json. Каждый раз, когда добавляется новая папка, она добавляется в массив JSON.

Если говорить точнее, в моем случае у меня есть корневая (целевая) корзина, в которой будет ряд папок, созданных Elemental MediaConvert. Каждая папка представляет новое видео; и внутри каждой папки находятся различные форматы, которые могут быть поданы на разные устройства. Вернувшись на корневой уровень, у меня есть index.json, который представляет собой массив этих видео папок; это индекс контента. Теперь я могу изменить лямбду, которая является частью потока MediaConvert ... но я рассмотрю это в другой раз. Здесь я просто хочу запускать новую лямбду S3 каждый раз, когда MediaConvert записывает новую папку видео ... это просто случайный GUID.

Я изучаю Node JS, и я впервые использую некоторые структуры и звонки, которые вы видите здесь. (По крайней мере, я знаю, что эта форма чище и понятнее, чем использование обратных вызовов.)

Поскольку будет сложно (для меня!) Проверить это как функцию Lambda, кто-то любезно укажет мне на любые очевидные ошибки ??

Кроме того, кто-нибудь подскажет, как вручную протестировать эту лямбда-функцию с использованием данных событий Amazon S3 (до настройки фактического сегмента для публикации требуемого события)? Я думаю, мне нужен файл 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");
        }
    );
};

UPDATE Я отказался от этого подхода в пользу обновления индекса контента с помощью другого средства, которое не рискует безудержным выполнением моей лямбды. Я обнаружил из первых рук, что не стоит пытаться инициировать конкретное событие createObject в корзине, когда в его дизайне не предусмотрен надежный фильтр уведомлений о событиях. (Я не мог отфильтровать суффикс простого /.) Кроме того, я ожидал, что одно событие создания объекта ключа папки вызовет мою лямбду, но в действительности другие папки и ключи создали внутри , что новый папка корневого уровня тоже запустила мою лямбду. Итак, это отправило меня в рабочий процесс преобразования видео, чтобы изменить лямбду, которая уведомляет об успешном завершении рабочего процесса, так что он обновляет мой индекс контента.

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Ваша лямбда будет срабатывать только при создании / удалении / изменении нового объекта в корзине в зависимости от вашей конфигурации. Если вы создадите новую папку в корзине, она не будет запускать вашу лямбду. Вы можете упростить свой код, используя синтаксис async / await во время выполнения Lambda Node.js 8.1.

Лямбда-обработчик

var AWSS3 = require('aws-sdk/clients/s3');
const CONTENT_INDEX_FILENAME = 'index.json';
var s3 = new AWSS3();

exports.handler = async (event) => {

  try {
    console.log('Event', JSON.stringify(event));

    // Bucket name.
    const triggerBucket = event.Records[0].s3.bucket.name;

    // New key added.
    const newKey = event.Records[0].s3.object.key;

    // Assuming only folder name is to be added in the list. If object 
    // is added in the bucket root then it will be ignored.
    if (newKey.indexOf('/') > -1) {

      // Get existing data.
      let existing = await s3.getObject({
        Bucket: triggerBucket,
        Key: CONTENT_INDEX_FILENAME
      }).promise();

      // Parse JSON object.
      let existingData = JSON.parse(existing.Body);

      // Get the folder name.
      const folderName = newKey.substring(0, newKey.indexOf("/"));

      // Check if we have an array.
      if (!Array.isArray(existingData)) {
        // Create array.
        existingData = [];
      }

      existingData.push(folderName);

      await s3.putObject({
        Bucket: triggerBucket,
        Key: CONTENT_INDEX_FILENAME,
        Body: JSON.stringify(existingData),
        ContentType: 'application/json'
      }).promise();

      console.log(`Added new folder name ${folderName}`);

      return folderName;

     } else {
         console.log('Key was added in bucket root.');
         return 'Ignored';
     }
    };
  }
  catch(err) {
    return err;
  }

Работает локально:

Создайте файл event.json в корне вашего проекта. Добавьте следующее в event.json.

{
  "Records":[
    {
      "s3":{
        "bucket":{
        "name": "your_bucket_name"
    },
    "object":{
      "key": "your_folder/your_file.json"
    }
   }
  }
 ]
}

Глобальная загрузка лямбда-пакета.

npm install -g lambda-local

Наконец, проверьте это:

Запускать функцию локально, передавая файл event.json, созданный выше.

lambda-local -l path/to/function.js -e event.json

0 голосов
/ 07 января 2019

Что касается локального тестирования, я ранее использовал https://www.npmjs.com/package/aws-lambda-local, и он отлично работал для меня.

Просто сверьтесь с документами AWS, например, данные S3 json data

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...