Лямбда-функция для распаковки файлов из корзины S3.

Уже несколько дней мне интересно, как загрузить несколько файлов с клиентской стороны моего веб-приложения. И я нашел аналогичный вопрос на StackOverflow, но принятый ответ был реализован с использованием интерфейса командной строки AWS. Я, безусловно, могу реализовать это с помощью CLI через дочерние процессы, использующие Node.js в бэкэнде. Но наверняка существует лучший и более быстрый подход, чем этот.

В другой статье говорилось о загрузке с использованием promise.all , но это определенно не вариант на стороне клиента. Я также нашел некоторую реализацию с использованием python и boto3, но мое приложение было написано на Node.js, поэтому я не могу позволить себе добавить еще один язык в свой список зависимостей. Потом поискал еще на эту тему и нашел эту статью автора Акмал Шарипов. Конечно, его статья была полезной, но я столкнулся с некоторыми проблемами при использовании этой библиотеки (возможно, я виноват в том, как я ее реализовал).

Немного покопавшись, я обнаружил, что структура zip-файла имеет центральный каталог, расположенный в конце файла, и существуют локальные заголовки, которые являются копией центрального каталога, но крайне ненадежны. И методы чтения большинства других потоковых библиотек буферизуют весь zip-файл в памяти, таким образом, в первую очередь нарушая всю цель его потоковой передачи. Итак, вот еще один алгоритм, который я придумал, используя библиотеку yauzl, которую он также упомянул в своей статье.

  1. Пользователь загружает множество файлов через мое приложение.
  2. Мое приложение сжимает эти файлы с помощью библиотеки yazl и загружает их в корзину S3 на стороне клиента.
  3. Событие S3 «put» запускает лямбда-функцию.
  4. Лямбда-функция загружает весь объект (zip-файл) в свой буфер памяти.
  5. Он считывает одну запись и загружает ее обратно в S3.
  6. Когда загрузка завершается, она переходит к следующей записи и повторяет шаг 5.

Этот алгоритм никогда не достигает предела оперативной памяти лямбда-функции. Максимальное использование памяти составляло менее 500 МБ для извлечения zip-файла размером 254 МБ, содержащего 2,24 ГБ файлов.

Создайте лямбда-функцию и добавьте триггер S3.

Перед созданием лямбда-функции создайте роль IAM с полными разрешениями S3 и лямбда. Теперь перейдите в раздел лямбда-сервисов и нажмите кнопку «Создать функцию» в правом верхнем углу. На следующей странице выберите «Автор с нуля» и дайте название функции. В разделе «Разрешения» выберите «использовать существующую роль» и выберите роль, которую вы определили ранее — вы всегда можете изменить разрешение позже. Затем нажмите кнопку «Создать функцию» в правом нижнем углу страницы.

Настройте функцию Lambda таким образом, чтобы она запускалась всякий раз, когда zip-файл загружается в корзину S3. Нажмите кнопку «Добавить триггер» в разделе «Обзор функций» и выберите событие S3 в раскрывающемся списке. Затем выберите свою корзину и выберите «PUT» в качестве типа события, а также не забудьте добавить «.zip» в поле суффикса, иначе функция будет автоматически вызывать функцию в цикле. Затем нажмите «Добавить», чтобы добавить триггер лямбда-функции.

Лямбда-функция для извлечения объектов из корзины S3

Мы будем использовать AWS SDK, чтобы получить файл из корзины S3. Внутри объекта event функции-обработчика у нас есть массив Records, содержащий имя корзины S3 и ключ объекта, вызвавшего эту лямбда-функцию. Мы будем использовать массив Records для получения корзины и ключ для метода S3.getObject(params, [callback]) для извлечения zip-файла.

Загрузить объект в корзину S3 из потока

Это основная часть кода, которая была немного сложной. Судя по всему, передача читаемого потока напрямую в свойство Body параметра params не работает, по крайней мере, в лямбда-окружении. Итак, я поискал в GOOGLE — как обычно — и нашел этот вопрос о StackOverflow, который идеально соответствует моим требованиям. Вот код.

Чтобы использовать эту функцию, нам нужно сначала вызвать функцию, а затем передать читаемый поток в возвращаемое ею свойство writeStream.

Разархивируйте объект и загрузите каждую запись обратно на S3.

Библиотека Яузл — самая популярная библиотека в реестре npm. Эта библиотека также очень надежна, и я не хочу, чтобы мое приложение вылетало из-за какой-то глупой проблемы с библиотекой. Документация также очень удобна для пользователя. Я буду использовать метод fromBuffer, так как zip-файл будет доступен нам только через буфер. Давайте погрузимся в код для распаковки файла.

Эта функция будет считывать одну запись из zip-файла, а затем загружать ее обратно в корзину S3 с помощью функции uploadStream, которую мы реализовали ранее. После завершения загрузки одной записи/файла только она будет читать следующую запись и загружать ее, и цикл будет продолжаться до тех пор, пока не будет достигнут конец zip-файла. Он разрешает обещание с сообщением «конец», когда в zip-файле ничего не осталось.

Собираем все вместе



Весь код доступен в указанном выше репозитории. Вам просто нужно клонировать репозиторий, а затем запустить npm install, а затем npm run zip. Затем загрузите файл lambda.zip в раздел лямбда-кода консоли.

Не волнуйтесь, если вы не хотите клонировать мой репозиторий, вы можете вставить все функции, которыми я поделился, в файл index.js и заменить console.log(object) в строке 15 файла 'exports.handler' этой строкой const result = await extractZip(Bucket, object.Body);

.

Последние слова

Я просто реализовал алгоритм немного иначе, чем в другой реализации, которую я обсуждал ранее. Мой подход заключался в том, чтобы не передавать zip-файл, а передавать записи по одной за раз. Но все остальные алгоритмы тоже хороши.

Если вы найдете эту статью полезной, не забудьте поставить мне лайк. И вот еще одна статья, которая может вам понравиться.



Удачного взлома!

Дополнительные материалы на plainenglish.io