【问题标题】:Invoke an AWS Lambda function only after an Amazon DynamoDB export to Amazon S3 is totally complete仅在将 Amazon DynamoDB 导出到 Amazon S3 完全完成后才调用 AWS Lambda 函数
【发布时间】:2021-11-14 10:23:25
【问题描述】:

总的来说,我是 AWS 和云技术的新手。所以,如果下面的用例是微不足道的,请多多包涵。

嗯,我在 Amazon DynamoDB 中有一个表,我每天早上 6 点使用 exportTableToPointInTime API (ExportsToS3) 将其导出到 Amazon S3。正在以这种方式使用 AWS Lambda 函数完成 -

const AWS = require("aws-sdk");

exports.handler = async (event) => {

    const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
    const tableParams = {
        S3Bucket: '<s3-bucket-name>',
        TableArn: '<DynamoDB-Table-ARN>',
        ExportFormat: 'DYNAMODB_JSON'
    };

    await dynamodb.exportTableToPointInTime(tableParams).promise();
};

AWS Lambda 函数的 CFT 模板负责创建 lambda 角色和策略等,以及使用 Cloudwatch 事件进行调度。此设置有效,并且表每天在预定时间导出到目标 Amazon S3 存储桶。

现在,我想要的下一件事是,在导出到 Amazon S3 完成后,我应该能够调用另一个 lambda 函数并将导出状态传递给该 lambda 函数,该函数对其进行一些处理。

我面临的问题是,上面的 lambda 函数几乎立即完成执行,exportTableToPointInTime 调用返回状态为 IN_PROGRESS。

我尝试捕获上述调用的响应,例如 -

const exportResponse = await dynamodb.exportTableToPointInTime(tableParams).promise();
console.log(exportResponse);

这个的输出是 -

{
    "ExportDescription": {
        "ExportArn": "****",
        "ExportStatus": "IN_PROGRESS",
        "StartTime": "2021-09-20T16:51:52.147000+05:30",
        "TableArn": "****",
        "TableId": "****",
        "ExportTime": "2021-09-20T16:51:52.147000+05:30",
        "ClientToken": "****",
        "S3Bucket": "****",
        "S3SseAlgorithm": "AES256",
        "ExportFormat": "DYNAMODB_JSON"
    }
}

我只是用 **** 混淆了日志中的一些值

可以看出,exportTableToPointInTime API 调用不会等待表完全导出。如果有,它会将 ExportStatus 返回为 COMPLETED 或 FAILED。

有没有一种方法可以设计上述用例来实现我的要求 - 在导出实际完成时调用另一个 lambda 函数?

到目前为止,我已经尝试了一种蛮力的方法来做到这一点并且可行,但它肯定似乎效率低下,因为它在那里进入睡眠状态,并且 lambda 函数在导出的整个期间都在运行,导致成本影响。

exports.handler = async (event) => {

    const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
    const tableParams = {
        S3Bucket: '<s3-bucket-name>',
        TableArn: '<DynamoDB-Table-ARN>',
        ExportFormat: 'DYNAMODB_JSON'
    };

    const exportResponse = await dynamodb.exportTableToPointInTime(tableParams).promise();

    const exportArn = exportResponse.ExportDescription.ExportArn;
    let exportStatus = exportResponse.ExportDescription.ExportStatus;
    
    const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
    
    do {
        await sleep(60000); //waiting every 1 min and then calling listExports API
        const listExports = await dynamodb.listExports().promise();
        const filteredExports = listExports.ExportSummaries.filter(e => e.ExportArn == exportArn);
        const currentExport = filteredExports[0];
        exportStatus = currentExport.ExportStatus;
    }
    while (exportStatus == 'IN_PROGRESS');

    var lambda = new AWS.Lambda();
    var paramsForInvocation = {
        FunctionName: 'another-lambda-function',
        InvocationType: 'Event',
        Payload: JSON.stringify({ 'ExportStatus': exportStatus })
    };

    await lambda.invoke(paramsForInvocation).promise();
};

可以做些什么来改善它或者上面的解决方案可以吗?

谢谢!!

【问题讨论】:

  • 您可以让您的第二个 Lambda 函数由 this example 中的 S3 事件触发吗? S3 事件只会在 S3 文件创建完成时触发
  • 如果由于某种原因导出到 s3 API 失败怎么办?我猜在那种情况下它不会创建 S3 文件,对吧?

标签: amazon-web-services amazon-s3 aws-lambda amazon-dynamodb


【解决方案1】:

对于等待调用,您在处理程序上缺少“async”关键字。 改变

exports.handler = (event) => {

exports.handler = async event => {

因为这是一个等待调用,所以你需要'async'关键字。

如果它解决了您的问题,请告诉我。

另外,我怀疑您不需要.promise(),因为它可能已经返回承诺。无论如何,请尝试使用和不使用它,以防它仍然无法正常工作。

在 dynamoDB await 调用之后,您可以调用另一个 lambda。它将确保在 dynamoDb 导出调用完成后调用您的 lambda。

调用第二个 lambda,

  • 您可以使用 aws sdk 调用包。
  • putEvent api 使用 eventBridge。

后一个选项更好,因为它解耦了两个 lambda,而且,第一个 lambda 不必等到秒调用完成。 (减少 lambda 时间,从而降低成本)

【讨论】:

  • 我在问题中错误地提到了没有异步。实际代码已经在处理程序上有异步。在 exportTableToPointInTime API 调用上尝试不使用 .promise() 实际上根本不会触发导出。
【解决方案2】:

实现此目的的一个选项是定义一个服务员,以便等待exportTableToPointInTime 返回“已完成”状态。

据我所知,已有一些默认的 DynamoDB 服务员,但没有用于导出的服务员,因此您需要自己编写 (you can use those already present as an example)。

一篇很好的帖子,描述了如何使用和编写服务员could be found here

这样,如果导出时间少于 15 分钟,您就可以在 Lambda 限制内捕获它,而无需辅助 lambda。

如果需要更长的时间,您需要将其解耦,您可以根据@Schepo 和@wahmd 的建议有多个选项:

  • 在另一端使用 S3 事件
  • 使用 AWS EventBridge
  • 使用 SNS
  • 以上的组合。

【讨论】:

  • 谢谢,我会试一试,看看效果如何。正如我所说,我对 AWS 很陌生。也就是说,在导出完全完成之前,这种方法仍然会产生 lambda 执行成本,对吧?
  • 说的没错,不过应该比你现在这样睡觉要清晰一点,也快一点。在您的情况下,您只需等待 x 时间,而在这种情况下,您将每 Y 秒轮询一次 API,直到看到成功。
【解决方案3】:

上下文:我们希望将 DynamoDB 表 content 导出到 S3 存储桶中,并在导出完成时触发 lambda。

在 CloudTrail 中有一个ExportTableToPointInTime 事件在导出开始时发送,但在导出完成时没有事件。

导出完成后触发 lambda 的一种方法是使用以下配置创建 S3 触发器:

特别是:

  • 创建事件类型是完整的多次上传(其他的好像不行,不知道为什么)。
  • 我认为前缀可以省略,但它很有用。它由以下部分组成:
    • 第一部分是表名,content
    • 第二部分AWSDynamoDB由导出工具自动设置。
  • 这是最重要的部分。导出完成后创建的最后一个文件是 manifest-summary.jsonmanifest-summary.md5。我们必须将后缀设置为这些文件之一。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    • 2011-07-05
    相关资源
    最近更新 更多