S3批量上传图片仅部分触发Lambda执行处理问题求助
问题根因定位
1. 核心代码逻辑错误(最主要原因)
- 未处理SQS批量推送的所有消息:SQS触发Lambda时默认一次推送最多10条记录,你的代码只取了
event.Records[0]处理,剩下的记录直接被丢弃,自然会出现少处理文件的情况 - 异步操作未等待完成就提前返回:你的代码中调用第三方去背景接口的
request、上传结果到S3的s3.upload都是回调式异步操作,你没有等待这些操作执行完成就直接调用callback(null, 'All done!'),Lambda会直接冻结执行环境,未完成的异步逻辑会被终止,导致看起来没有触发处理 - 错误处理不完善:代码中仅打印错误,没有抛出异常或者返回处理失败标识,SQS会认为消息已经处理成功,不会重试失败的任务
2. 配置类可能的问题
- S3事件通知配置不全:如果你的上传用到了分片上传、复制文件等操作,但事件通知只配置了
s3:ObjectCreated:Put,没有包含s3:ObjectCreated:MultipartUploadComplete、s3:ObjectCreated:Copy等事件,部分上传操作不会触发通知 - SQS配置不合理:如果SQS的可见性超时小于Lambda的执行时长,消息还没处理完就会被SQS重新投放,或者没有配置死信队列,多次处理失败的消息直接丢失无法排查
- Lambda资源配置不足:如果Lambda超时时间设置过短、内存不足,处理大图片时会超时或者OOM被强制终止,也会导致处理失败
修复方案
代码修复示例
// 首先把回调式方法包装成Promise const util = require('util'); const requestPromise = util.promisify(request); const s3UploadPromise = util.promisify(s3.upload).bind(s3); exports.handler = async (event, context) => { // 遍历所有Records,不要只取第一条 for (const record of event.Records) { try { console.log(record); const json = JSON.parse(record['body']); console.log('json: '+json); const s3Info = JSON.parse(json['Message'])['Records'][0]['s3']; console.log(s3Info); const srcBucket = s3Info['bucket']['name']; console.log('srcBucket: ' + srcBucket); const srcKey = decodeURIComponent(s3Info['object']['key'].replace(/\+/g, ' ')); console.log('srcKey: ' + srcKey); const str = (srcKey.split('/').pop()).split('.')[0]; console.log('str: ' + str); if (str === '') continue; const folderPath = srcKey.substr(srcKey.indexOf('/') + 1).split('.')[0].substring(0, folderPath.lastIndexOf('/')); console.log('folderPath: ' + folderPath); const params1 = { Bucket: srcBucket, Key: srcKey }; const origimage = await s3.getObject(params1).promise(); const destKey = 'removebg/' + folderPath + '/' + str + '.jpg'; const options = { 'method': 'POST', 'url': 'https://api.remove.bg/v1.0/removebg', 'headers': { 'X-Api-Key': 'xxxxxxxxxxx' }, formData: { 'image_file': origimage.Body, 'size': 'auto' }, encoding: null }; // 等待第三方接口调用完成 const response = await requestPromise(options); if (response.statusCode !== 200) { throw new Error(`Remove bg failed, status: ${response.statusCode}, body: ${response.body}`); } // 等待S3上传完成 await s3UploadPromise({ Bucket: destBucket, Key: destKey, Body: response.body }); console.log('Successfully uploaded data to ' + destBucket); } catch (e) { console.error('处理消息失败', e); // 抛出错误,让SQS知道消息处理失败,可重试 throw e; } } // 所有消息处理完成再返回 return 'All done!'; };
配置检查项
- 检查S3事件通知配置,确认事件类型选择了
s3:ObjectCreated:*,前缀配置为a/,没有多余的过滤规则 - 调整SQS配置:可见性超时设置为Lambda超时时间的1.5倍以上,配置死信队列存储多次处理失败的消息方便排查
- 调整Lambda配置:超时时间根据单张图片的处理时长 * 批量大小设置,内存建议至少配置512MB以上,避免OOM
- 如果不需要批量处理,可将SQS的批量接收大小设置为1,每次只推送1条消息给Lambda
内容的提问来源于stack exchange,提问作者Rashmi
相关产品推荐
相关产品推荐

