Lambda2调用S3 HeadObject报404,疑文件未同步完成
解决Lambda2因S3文件未就绪导致的404错误
问题场景
Lambda1调用AWS Transcribe生成SRT文件并存入S3,随后将文件存储位置传递给Lambda2;Lambda2尝试下载该文件时触发ClientError: An error occurred (404) when calling the HeadObject operation: Not Found错误。但直接用S3触发器触发Lambda2时代码可正常运行,核心原因是Transcribe生成的SRT文件尚未完全写入S3,Lambda2就开始执行下载操作。
解决方案
方案1:改用S3事件触发器替代Lambda直接调用
既然S3触发器能保证文件写入完成后再触发Lambda2,可调整架构:
- 让Lambda1仅负责启动Transcribe任务,无需直接调用Lambda2
- 给存储SRT文件的S3桶配置
s3:ObjectCreated:*事件,将Lambda2设为事件目标 - 好处:完全由S3的事件机制保证文件就绪后再执行处理逻辑,从根源避免时序问题
方案2:在Lambda2中添加重试机制
如果必须保留Lambda1调用Lambda2的链路,可在下载逻辑中加入重试逻辑,等待文件就绪:
import boto3 import urllib.parse from botocore.exceptions import ClientError import time s3 = boto3.resource('s3') def lambda_handler(event, context): source_bucket_name = event['responsePayload']['BucketDestination'] file_name = urllib.parse.unquote_plus(event['responsePayload']['ObjectKey']) source_file = '/tmp/source.srt' # 配置重试参数:最多5次,每次间隔2秒 max_retries = 5 retry_count = 0 while retry_count < max_retries: try: source_object = s3.Object(source_bucket_name, file_name) source_object.download_file(source_file) print("文件下载成功") break except ClientError as e: if e.response['Error']['Code'] == '404': retry_count += 1 print(f"文件未找到,第{retry_count}次重试...") time.sleep(2) else: # 非404错误直接抛出 raise else: # 重试耗尽仍失败,抛出异常 raise Exception(f"重试{max_retries}次后仍无法找到文件:{file_name}")
- 注意:需将Lambda2的执行超时时间设置为足够长(建议至少15秒),避免重试过程中被强制终止
方案3:让Lambda1等待Transcribe任务完成再调用Lambda2
修改Lambda1逻辑,轮询等待Transcribe任务完成后,再调用Lambda2:
import boto3 import json import time transcribe = boto3.client('transcribe') lambda_client = boto3.client('lambda') def lambda_handler(event, context): # 启动Transcribe任务的原有逻辑 job_name = 'test_short49' transcribe.start_transcription_job( TranscriptionJobName=job_name, Media={'MediaFileUri': 's3://your-input-bucket/input-file.mp3'}, OutputBucketName='bucket-1', OutputKey='test_short49', Subtitles={'Formats': ['srt']} ) # 轮询等待任务完成 while True: job_status = transcribe.get_transcription_job(TranscriptionJobName=job_name)['TranscriptionJob']['TranscriptionJobStatus'] if job_status in ['COMPLETED', 'FAILED']: break time.sleep(3) if job_status == 'COMPLETED': # 获取最终SRT文件的存储位置 bucket = 'bucket-1' object_key = f"{job_name}.srt" # 调用Lambda2 lambda_client.invoke( FunctionName='Lambda2', Payload=json.dumps({ 'responsePayload': { 'BucketDestination': bucket, 'ObjectKey': object_key } }) )
- 注意:需根据Transcribe任务的预期耗时,设置Lambda1的超时时间(比如如果任务通常需要1分钟,超时设为2分钟)
内容的提问来源于stack exchange,提问作者user3324136
相关产品推荐
相关产品推荐

