首页 > 解决方案 > 如果我不首先使用 Promises 通过 AWS NodeJS Lambda 终端节点上传一张图片,则无法将多张图片上传到 AWS S3

问题描述

我在 AWS Lambda 上有以下代码作为通过 API Gateway 公开的端点。此端点的目的是将图像上传到 S3 存储桶。我遇到了一个有趣的错误,可以使用一些帮助。如果不先上传一张图片,此代码将无法将多张图片上传到 S3。我列出了下面的场景。我想使用 Promises 的原因是因为我打算将数据插入到同一端点的 mysql 表中。任何建议或反馈将不胜感激!

代码成功上传多张图片

  1. 将一张图片传递给端点以先上传到S3
  2. 先上传一张图片后,将多张图片传到endpoint上传到S3

代码无法上传图片

  1. 将几张图像传递给端点以首先上传到 s3 。可能会上传随机数量的图像,但始终无法上传所有图像。上传所有图片失败,返回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")
    }
};

标签: node.jsamazon-s3promiseaws-lambdaaws-sdk-nodejs

解决方案


问题原因及解决方法

经过几个小时的调试这个问题,我意识到错误是什么!我的 Lambda 端点提前超时。我在第一次上传一张图片后能够上传多张图片的原因是我的 lambda 端点是从热启动开始执行的——因为它已经启动并运行了。我无法上传多张图片的情况实际上只发生在我在 10 多分钟内未执行端点后尝试这样做时——因此是冷启动。因此,解决方案是从默认的 3 秒增加超时。我将它增加到 20 秒,但可能需要玩弄那个时间。

如何增加 lambda 超时?

  1. 打开 Lambda 函数
  2. 向下滚动到基本设置并选择编辑
  3. 增加超时时间

TLDR

发生此错误是因为 Lambda 会超时。解决方案是增加 lambda 超时。


推荐阅读