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

S3触发Lambda删除对象失败,手动测试正常求助

问题描述

我有一个由S3 Put事件触发的Lambda函数,文件上传至存储桶后会检查对象键的扩展名,未通过则执行删除。发现S3自动触发时,文件有时仍留存且带删除标记;但手动用测试按钮运行(含上传事件数据)每次都能成功删除。已添加15秒延迟仍无效,附上相关代码及日志,求解决方案。

相关代码

主Lambda代码片段

# 提取存储桶名称、对象键和版本ID
bucket_name = record['s3']['bucket']['name']
object_key = record['s3']['object']['key']
version_id = record['s3']['object']['versionId']

# 删除所有版本前短暂暂停
time.sleep(15) 

print(f"文件 {object_key} 扩展名无效,将从存储桶 {bucket_name} 删除。") 

# 先删除对象——可能会添加删除标记
response = s3_client.delete_object(Bucket=bucket_name, Key=object_key, VersionId=version_id)
print(f"已从 {bucket_name} 删除版本 {version_id} 的 {object_key}。")
print("实际响应如下:")
print(response)

# 删除所有版本前短暂暂停
time.sleep(3)

# 调用函数删除所有版本(因为存储桶开启了版本控制)
delete_all_versions_new(bucket_name, object_key)

delete_all_versions_new函数代码

def delete_all_versions_new(bucket_name, object_key):
    """从开启版本控制的S3存储桶中删除对象的所有版本。"""
    s3_client = boto3.client('s3')
    try:
        # 列出对象的所有版本
        versions = s3_client.list_object_versions(Bucket=bucket_name, Prefix=object_key)
        if 'Versions' in versions:
            for version in versions['Versions']:
               s3_client.delete_object(Bucket=bucket_name, Key=object_key, VersionId=version['VersionId'])
               print(f"已从 {bucket_name} 删除 {object_key} 的版本 {version['VersionId']}。")
        if 'DeleteMarkers' in versions:
            for marker in versions['DeleteMarkers']:
              s3_client.delete_object(Bucket=bucket_name, Key=object_key, VersionId=marker['VersionId'])
              print(f"已从 {bucket_name} 删除 {object_key} 的删除标记 {marker['VersionId']}。")
    except Exception as e:
        print(f"从 {bucket_name} 删除 {object_key} 的所有版本失败:{e}")

日志输出

文件 RSTMT/ASP_SUBMITTER/Q2+2023/DUA-Blank.pdf 扩展名无效,将从存储桶删除(暂停后)。
已从存储桶删除版本 wp3CRB_gJwsCPGpDJQ9Bjvyus5N3d6V2 的 KEY/ASP_SUBMITTER/Q2+2023/DUA-Blank.pdf。
实际响应如下:
{'ResponseMetadata': {'RequestId': 'S0Y16H5YZCNCHJW6', 'HostId': 'xxxx', 'HTTPStatusCode': 204, 'HTTPHeaders': {'x-amz-id-2': '', 'x-amz-request-id': '', 'date': 'Fri, 09 May 2025 02:54:26 GMT', 'x-amz-version-id': '', 'server': 'AmazonS3'}, 'RetryAttempts': 0}, 'VersionId': 'wp3CRB_gJwsCPGpDJQ9Bjvyus5N3d6V2'}
END RequestId: ...

解决方案

1. 替换time.sleep(),改用S3一致性等待

S3触发Lambda时存在最终一致性问题——Lambda启动后,对象的版本元数据可能还未完全同步。time.sleep()不可靠,改用S3 waiter等待对象版本可用:

# 替换time.sleep(15),等待目标版本存在
s3_client.get_waiter('object_exists').wait(
    Bucket=bucket_name,
    Key=object_key,
    VersionId=version_id
)

2. 修复delete_all_versions_new的前缀匹配问题

当前用Prefix=object_key会误删所有前缀匹配的对象(比如a/b会匹配a/b/c),需精确匹配对象键,同时处理分页结果:

def delete_all_versions_new(bucket_name, object_key):
    s3_client = boto3.client('s3')
    try:
        paginator = s3_client.get_paginator('list_object_versions')
        page_iterator = paginator.paginate(Bucket=bucket_name, Prefix=object_key)
        
        for page in page_iterator:
            # 精确匹配对象键,避免误删
            if 'Versions' in page:
                for version in page['Versions']:
                    if version['Key'] == object_key:
                        s3_client.delete_object(Bucket=bucket_name, Key=object_key, VersionId=version['VersionId'])
                        print(f"已从 {bucket_name} 删除 {object_key} 的版本 {version['VersionId']}。")
            if 'DeleteMarkers' in page:
                for marker in page['DeleteMarkers']:
                    if marker['Key'] == object_key:
                        s3_client.delete_object(Bucket=bucket_name, Key=object_key, VersionId=marker['VersionId'])
                        print(f"已从 {bucket_name} 删除 {object_key} 的删除标记 {marker['VersionId']}。")
    except Exception as e:
        print(f"从 {bucket_name} 删除 {object_key} 的所有版本失败:{e}")

3. 简化删除逻辑

无需先删除对象再清理版本,直接删除触发事件的版本,再调用修复后的全版本删除函数:

print(f"文件 {object_key} 扩展名无效,将从存储桶 {bucket_name} 删除。") 
# 直接删除触发事件的目标版本
s3_client.delete_object(Bucket=bucket_name, Key=object_key, VersionId=version_id)
print(f"已从 {bucket_name} 删除版本 {version_id} 的 {object_key}。")
# 清理剩余版本和删除标记
delete_all_versions_new(bucket_name, object_key)

4. 检查Lambda权限

确保Lambda角色拥有s3:DeleteObject、s3:ListObjectVersions权限,且策略覆盖存储桶的所有版本操作。


内容的提问来源于stack exchange,提问作者Brian Edwards

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:05:00