node.js - 如果我不首先使用 Promises 通过 AWS NodeJS Lambda 终端节点上传一张图片,则无法将多张图片上传到 AWS S3
问题描述
我在 AWS Lambda 上有以下代码作为通过 API Gateway 公开的端点。此端点的目的是将图像上传到 S3 存储桶。我遇到了一个有趣的错误,可以使用一些帮助。如果不先上传一张图片,此代码将无法将多张图片上传到 S3。我列出了下面的场景。我想使用 Promises 的原因是因为我打算将数据插入到同一端点的 mysql 表中。任何建议或反馈将不胜感激!
代码成功上传多张图片:
- 将一张图片传递给端点以先上传到S3
- 先上传一张图片后,将多张图片传到endpoint上传到S3
代码无法上传图片:
- 将几张图像传递给端点以首先上传到 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")
}
};
解决方案
问题原因及解决方法:
经过几个小时的调试这个问题,我意识到错误是什么!我的 Lambda 端点提前超时。我在第一次上传一张图片后能够上传多张图片的原因是我的 lambda 端点是从热启动开始执行的——因为它已经启动并运行了。我无法上传多张图片的情况实际上只发生在我在 10 多分钟内未执行端点后尝试这样做时——因此是冷启动。因此,解决方案是从默认的 3 秒增加超时。我将它增加到 20 秒,但可能需要玩弄那个时间。
如何增加 lambda 超时?
- 打开 Lambda 函数
- 向下滚动到基本设置并选择编辑
- 增加超时时间
TLDR
发生此错误是因为 Lambda 会超时。解决方案是增加 lambda 超时。
推荐阅读
- excel - Excel (VBA?) - 自定义单元格格式、数字和文本间距
- reactjs - setState() 导致状态变量未定义
- angular - Angular 7将对象与对象数组映射到垫表
- javascript - JavaScript:在进度条上停止动画
- firebase - 从将数据推送到您打开的 websocket 的提供程序将外部数据导入 Firestore?
- sql - where 语句取消了结果?
- scala - Kubernetes kafka - lagom - 消费者在超时后因 WakeupException 而中断。消息:空
- ios - view.addSubview(: ) Not working in swift playgrounds
- asp.net-core - Automapper v8 不忽略 EF(实体框架)类的导航属性
- arrays - 在 VBA 中存储字符串并输出到多个单元格