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

JS编写AWS Lambda删除版本化S3存储桶对象未生效问题排查

问题排查结论

你的代码存在4个核心问题,导致S3删除逻辑根本没有实际执行完成:

  • 异步逻辑未等待:Array.forEach 不会等待内部async回调执行,Lambda在handler函数同步代码执行完后会立即冻结运行环境,你发起的S3请求还没拿到响应就被终止,这是最核心的原因。同时你所有S3 API调用都没有加await,.promise()仅将SDK请求转为Promise对象,不await的话代码不会等待请求返回,打印的"删除成功"日志是提前输出的无效日志,实际请求结果、报错都不会被捕获。
  • 无效的Promise调用:_processRecord本身是async函数,返回值就是原生Promise,你额外调用.promise()会直接抛出静默错误,因为自定义async函数没有这个SDK专属方法。
  • 版本化S3桶删除逻辑错误:对开启版本控制的S3桶,不带VersionId调用deleteObject只会创建一个「删除标记」实现软删除,不会真正删除历史版本对象,控制台开启「显示所有版本」后就能看到原对象仍然存在;如果要彻底删除对象,必须指定版本ID删除所有对应版本。
  • 事件类型错误:DynamoDB Stream触发的Lambda事件不是APIGatewayEvent,类型定义错误容易导致字段读取异常。
修复方案
  1. 替换forEach为map+Promise.all,等待所有记录的处理逻辑全部执行完成后再让handler返回,避免Lambda提前终止进程
  2. 所有S3异步API调用前统一加await,确保请求执行完成后再走后续逻辑,正确捕获请求异常
  3. 修正版本化桶的删除逻辑:如果DynamoDB记录中存储了S3对象的版本ID,直接携带版本ID永久删除;如果未存储版本ID,先列出该Key下的所有版本(含删除标记),逐个删除所有版本
  4. 替换为正确的DynamoDB Stream事件类型,删除无效的.promise()调用
  5. 检查Lambda执行角色权限,确保拥有s3:HeadObject、s3:ListBucketVersions、s3:DeleteObject、s3:DeleteObjectVersion 对应桶的操作权限
修复后参考代码
import { Context, DynamoDBStreamEvent } from 'aws-lambda';
const AWS = require('aws-sdk');
const s3 = new AWS.S3({
    region: 'eu-west-2'
});

export const handler = async (event: DynamoDBStreamEvent, context: Context) => {
  // 等待所有记录处理完成再返回
  await Promise.all(
    event.Records.map(async record => {
      if (record.eventName === "REMOVE" && record.dynamodb?.OldImage) {
        await _processRecord(record.dynamodb.OldImage);
      }
    })
  );
  return { statusCode: 200, body: 'Process completed' };
};

async function _processRecord(oldImage: Record<string, any>) {
    const bucketName = process.env.BUCKETNAME;
    const objectKey = oldImage.propertyId.S;
    try {
      // 先确认对象存在
      await s3.headObject({
        Bucket: bucketName,
        Key: objectKey
      }).promise();
      console.log(`Located S3 object: ${objectKey}`);

      // 列出该Key下所有版本(含删除标记)
      const versions = await s3.listObjectVersions({
        Bucket: bucketName,
        Prefix: objectKey
      }).promise();

      // 组装批量删除参数
      const deleteParams = {
        Bucket: bucketName,
        Delete: {
          Objects: [
            ...(versions.Versions || []).map(v => ({ Key: v.Key, VersionId: v.VersionId })),
            ...(versions.DeleteMarkers || []).map(v => ({ Key: v.Key, VersionId: v.VersionId }))
          ]
        }
      };

      if (deleteParams.Delete.Objects.length > 0) {
        await s3.deleteObjects(deleteParams).promise();
        console.log(`Successfully deleted all versions of ${objectKey}`);
      }
    } catch (error) {
      // 找不到对象直接跳过,其他错误打日志
      if ((error as any).code === 'NotFound') {
        console.log(`Object ${objectKey} not found in S3, skip deletion`);
        return;
      }
      console.log(`Process object ${objectKey} failed:`, error);
    }
}

注意:如果你的S3对象Key和propertyId不是完全匹配(比如有前缀、后缀),需要调整参数里的Key值,否则会找不到对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:51:17