使用GetObjectCommand时AWS Lambda提前终止,文件未全下载求助
问题分析与解决方案
核心问题
你的Lambda函数提前终止,是因为uploadFileForArchivePromise中的Promise在文件流尚未完全写入归档时就提前resolve了。当Promise.all收到所有Promise的resolve信号后,Lambda会继续执行后续逻辑,一旦后续代码执行完毕,进程就会被终止,此时未完成的文件流操作被强制中断,导致部分fileFinishedCount未触发,最终的"All Promise Finished"日志也无法输出。
小文件或少量文件时,流处理速度快,在Lambda终止前能完成,所以表现正常;但文件数量多或体积大时,流处理耗时更长,Lambda进程提前终止就会导致失败。
修复步骤
1. 调整Promise的resolve时机
将resolve()调用移至文件流的end事件回调中,确保只有当文件流完全写入归档后,Promise才会标记为完成:
function uploadFileForArchivePromise ({s3Path, pathInZip}, archive) { return new Promise((resolve, reject) => { const getObjectCommand = new GetObjectCommand({ Bucket: bucket, Key: s3Path }) s3.send(getObjectCommand).then(({Body}) => { fileLaunchedCount++ addLog('fileLaunchedCount = ' + fileLaunchedCount) addLog('file stream : ' + s3Path) Body.once('error', err => { addLog('addFilesToArchive - Body error:' + err) reject(err) }) Body.once('end', () => { fileFinishedCount++ addLog('fileFinishedCount = ' + fileFinishedCount) addLog('file stream : ' + s3Path) // 流处理完成后再resolve Promise resolve() }) archive.append(Body, {name: pathInZip}) }).catch((error) => { addLog('addFilesToArchive - s3 send getObjectCommand error:' + error) reject(error) }) }) }
2. 控制并发数(可选但推荐)
处理大量文件或大体积文件时,并行打开过多S3流可能导致资源耗尽。可以通过分批处理限制并发数,避免Lambda资源过载:
async function addFilesToArchive (files, archive) { try { addLog('addFilesToArchive - Starting batch processing') const batchSize = 10 // 可根据Lambda内存配置调整 // 分批处理文件 for (let i = 0; i < files.length; i += batchSize) { const batch = files.slice(i, i + batchSize) await Promise.all( batch.map((file) => uploadFileForArchivePromise(file, archive)) ) addLog(`addFilesToArchive - Completed batch ${Math.floor(i / batchSize) + 1}`) } addLog('addFilesToArchive - All Promise Finished') } catch (error) { console.error('Error reading files:', error) throw error } }
3. 完善归档错误监听
添加对归档对象的错误监听,避免静默失败:
// 在调用addFilesToArchive之前添加 archive.on('error', (err) => { addLog('Archive processing error:', err) throw err // 抛出错误以终止Lambda流程并记录日志 })
验证
修改后重新测试:
- 处理100个文件或大体积文件时,所有
fileFinishedCount都应触发 - "addFilesToArchive - All Promise Finished"日志会正常输出
- Lambda不会提前终止,直到所有文件流处理完成
内容的提问来源于stack exchange,提问作者Guillaume L.
相关产品推荐
相关产品推荐

