Невозможно загрузить несколько изображений на AWS S3, если я сначала не загружу одно изображение через конечную точку AWS NodeJS Lambda с помощью обещаний - PullRequest
0 голосов
/ 10 июля 2020

У меня есть приведенный ниже код на AWS Lambda в качестве конечной точки, доступной через API Gateway. Задача этой конечной точки - загрузить изображения в корзину S3. Я столкнулся с интересной ошибкой и мне нужна помощь. Этот код не может загрузить несколько изображений в S3, если он сначала не загрузит одно изображение. Я перечислил сценарий ios ниже. Причина, по которой я хочу использовать Promises, заключается в том, что я намереваюсь вставить данные в таблицу mysql в той же конечной точке. Будем очень благодарны за любые советы или отзывы!

Код успешно загружает несколько изображений :

  1. Передайте одно изображение конечной точке для загрузки в S3 первым
  2. Передать несколько изображений в конечную точку для загрузки в S3 после загрузки сначала одного изображения

Код не может загрузить изображения :

  1. Передайте несколько изображений в конечную точку для загрузки в s3 first . Может быть загружено произвольное количество изображений, но постоянно не удается загрузить их все. Код ошибки 502 возвращается, поскольку не удалось загрузить все изображения.

Код

const AWS = require('aws-sdk');
const s3 = new AWS.S3({});

function uploadAllImagesToS3(imageMap) {
    console.log('in uploadAllImagesToS3')
    return new Promise((resolve, reject) => {
        awaitAll(imageMap, uploadToS3)
            .then(results => {
                console.log('awaitAllFinished. results: ' + results)
                resolve(results)
            })
            .catch(e => {
                console.log("awaitAllFinished error: " + e)
                reject(e)
            })
   })
}

function awaitAll(imageMap, asyncFn) {
    const promises = [];
    imageMap.forEach((value, key) => {
        promises.push(asyncFn(key, value)); 
    })
    console.log('promises length: ' + promises.length)
    return Promise.all(promises)
}

function uploadToS3(key, value) {
    return new Promise((resolve, reject) => {
        console.log('Promise uploadToS3 | key: ' + key)
        // [key, value] = [filePath, Image]
        var params = {
            "Body": value,
            "Bucket": "userpicturebucket",
            "Key": key
        };
        s3.upload(params, function (err, data) {
            console.log('uploadToS3.  s3.upload. data: ' + JSON.stringify(data))
            if (err) {
                console.log('error when uploading to s3 | error: ' + err)
                reject(JSON.stringify(["Error when uploading data to S3", err]))
            } else {
                let response = {
                    "statusCode": 200,
                    "headers": {
                        "Access-Control-Allow-Origin": "http://localhost:3000"
                    },
                    "body": JSON.stringify(data),
                    "isBase64Encoded": false
                };
                resolve(JSON.stringify(["Successfully Uploaded data to S3", response]))
            }
        });
    })
}

exports.handler = (event, context, callback) => {
    if (event !== undefined) {
        let jsonObject = JSON.parse(event.body)
        let pictures = jsonObject.pictures
        let location = jsonObject.pictureLocation
        let imageMap = new Map()

        for (let i = 0; i < pictures.length; i++) {
            let base64Image = pictures[i].split('base64,', 2)
            let decodedImage = Buffer.from(base64Image[1], 'base64'); // image string is after 'base64'
            let base64Metadata = base64Image[0].split(';', 3) // data:image/jpeg,name=coffee.jpg,
            let imageNameData = base64Metadata[1].split('=', 2)
            let imageName = imageNameData[1]
            var filePath = "test/" + imageName
            imageMap.set(filePath, decodedImage)
        }

        const promises = [uploadAllImagesToS3(imageMap)]
        Promise.all(promises)
            .then(([uploadS3Response]) => {
                console.log('return promise!! | uploadS3Response: ' + JSON.stringify([uploadS3Response]))
                let res = {
                    body: JSON.stringify(uploadS3Response),
                    headers: {
                        "Access-Control-Allow-Origin": "http://localhost:3000"
                    }
                };
                callback(null, res);
            })
            .catch((err) => {
                callback(err);
            });
    } else {
        callback("No pictures were uploaded")
    }
};

1 Ответ

0 голосов
/ 10 июля 2020

Причина проблемы и решение :

После нескольких часов отладки этой проблемы я понял, в чем была ошибка! Моя конечная точка Lambda слишком рано отключилась. Причина, по которой я смог загрузить несколько изображений после первой загрузки одного изображения, заключалась в том, что моя конечная точка лямбда выполнялась с горячего старта, поскольку она уже была запущена. Сценарий, в котором мне не удавалось загрузить несколько изображений, на самом деле происходил только тогда, когда я пытался сделать это после того, как не выполнял конечную точку в течение 10+ минут - следовательно, холодный запуск. Поэтому решение заключалось в увеличении тайм-аута по умолчанию в 3 секунды. Я увеличил его до 20 секунд, но, возможно, придется поиграть с этим временем.

Как увеличить тайм-аут лямбда?

  1. Открыть лямбда-функцию
  2. Прокрутите вниз до Basi c Settings и выберите Edit
  3. Увеличить время ожидания

TLDR

Эта ошибка возникла из-за тайм-аута Lambda. Решение - увеличить тайм-аут лямбда.

...