Лямбда-функция для распаковки файлов из корзины S3.
Уже несколько дней мне интересно, как загрузить несколько файлов с клиентской стороны моего веб-приложения. И я нашел аналогичный вопрос на StackOverflow, но принятый ответ был реализован с использованием интерфейса командной строки AWS. Я, безусловно, могу реализовать это с помощью CLI через дочерние процессы, использующие Node.js в бэкэнде. Но наверняка существует лучший и более быстрый подход, чем этот.
В другой статье говорилось о загрузке с использованием promise.all
, но это определенно не вариант на стороне клиента. Я также нашел некоторую реализацию с использованием python и boto3, но мое приложение было написано на Node.js, поэтому я не могу позволить себе добавить еще один язык в свой список зависимостей. Потом поискал еще на эту тему и нашел эту статью автора Акмал Шарипов. Конечно, его статья была полезной, но я столкнулся с некоторыми проблемами при использовании этой библиотеки (возможно, я виноват в том, как я ее реализовал).
Немного покопавшись, я обнаружил, что структура zip-файла имеет центральный каталог, расположенный в конце файла, и существуют локальные заголовки, которые являются копией центрального каталога, но крайне ненадежны. И методы чтения большинства других потоковых библиотек буферизуют весь zip-файл в памяти, таким образом, в первую очередь нарушая всю цель его потоковой передачи. Итак, вот еще один алгоритм, который я придумал, используя библиотеку yauzl, которую он также упомянул в своей статье.
- Пользователь загружает множество файлов через мое приложение.
- Мое приложение сжимает эти файлы с помощью библиотеки yazl и загружает их в корзину S3 на стороне клиента.
- Событие S3 «put» запускает лямбда-функцию.
- Лямбда-функция загружает весь объект (zip-файл) в свой буфер памяти.
- Он считывает одну запись и загружает ее обратно в S3.
- Когда загрузка завершается, она переходит к следующей записи и повторяет шаг 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