You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 13:06:29