【问题标题】:How can I trigger one AWS Lambda function from another, guaranteeing the second only runs once?如何从另一个触发一个 AWS Lambda 函数,保证第二个只运行一次?
【发布时间】:2020-01-07 19:31:52
【问题描述】:

我使用无服务器框架构建了一些 AWS Lambda 函数管道。目前有五个步骤/功能,我需要它们按顺序运行,并且每个都只运行一次。大致的功能是:

  1. 通过 HTTP 请求触发函数,以 ID 响应。
  2. 访问和 API 以获取要下载的资源的 URL。
  3. 下载该资源并将副本上传到 S3。
  4. 更改该资源并将更改后的副本上传到 S3。
  5. 将更改的资源提交到不同的 API。

细节并不重要,但问题是:什么是最好的事件/触发器用于沿着这行函数向下移动?第一个是由 HTTP 调用触发的,但是第一个需要以某种方式触发第二个,然后第二个触发第三个,依此类推。

我使用 AWS SNS 编写了所有代码,但现在我已经将它部署到了 staging 中,我看到了 SNS often triggers more than once。我可以添加一堆代码来检测这一点,但我宁愿不这样做。而且问题也很复杂——如果第二个函数被触发两次,它会发送两个 SNS 通知来触发第三步。如果这些通知中的任何一个被加倍......最后一个函数可以被调用十次而不是一次并不是不合理的。

那么我最好的选择是什么?通过HTTP触发链?运动可能吗?我从未使用过除 HTTP 或 SNS 之外的触发器,所以我不确定我的选项是什么,以及哪些选项保证只会触发该函数一次。

【问题讨论】:

    标签: aws-lambda amazon-sns serverless-framework


    【解决方案1】:

    AWS Step Functions 似乎非常适合这种将单独的 AWS 操作绑定到具有明确错误处理的连贯工作流的用例。

    不确定定价是否适合您(可以是 pricey 进行数百万次以上的操作),但可能值得一看。

    也不确定性能开销或其他限制,所以 YMMV。

    【讨论】:

    • 我想知道 Step Functions 是否保证对 Lambda 任务的调用精确一次?我自己在文档中找不到任何提及。
    • 我对 Step Functions 的理解是,Step Functions 中的各个任务步骤仅使用一次语义调用(请参阅forums.aws.amazon.com/…),但确保您调用 Lambda 取决于您的任务实施恰好一次。
    【解决方案2】:

    在完成该步骤中所需的处理后,您可以在 lambda 函数中异步简单地触发下一个 lambda。

    因此,第一个 lambda 由 HTTP 调用触发,并且在该 lambda 执行中,完成此步骤的处理后,只需异步启动下一个 lambda 函数,而不是通过 SNS 或 Kinesis 发送触发器.在每个步骤中重复此过程。这将保证 lambda 一次性执行所有步骤。

    【讨论】:

    • 您是否建议通过HTTP触发每个功能,而只是发送请求而不等待响应?或者你的意思是“启动下一个 lambda”?想知道是否有办法启动我不知道的 lambda。
    • 基本上,我建议您使用 AWS SDK 通过代码异步启动 lambda 函数(异步启动时不能等待响应)。您的第一个函数由 HTTP 请求触发,在该函数中,您可以添加代码以异步启动第二个 lambda 函数。通过使用 AWS 开发工具包添加代码来修改您的 lambda 函数,以便它们异步启动管道中的下一个 lambda 函数。
    【解决方案3】:

    Eventful Lambda 触发器(SNS、S3、CloudWatch...)通常保证至少一次调用,而不是完全一次调用。正如您所指出的,您必须手动处理重复数据删除,例如,通过跟踪 DynamoDB 中的事件 ID(使用 strongly consistent reads!)或实现 idempotent Lambdas,这意味着没有额外的功能即使使用相同的输入多次调用也会产生影响。在您的示例中,步骤 4 本质上是幂等的,前提是该函数除了存储更改后的副本之外没有任何副作用,并且新副本会覆盖任何先前存储的具有相同事件 ID 的副本。

    SQS FIFO 是一种保证一次性交付开箱即用的服务。遗憾的是,该服务不能用于直接触发 Lambda,因此您必须设置一个计划的 Lambda 以定期轮询 FIFO 队列(根据 this answer)。在您的情况下,您可以通过这种安排处理第 5 步,因为我假设您不想多次向目标 API 提交相同的资源。

    总而言之,我会这样做:

    1. 通过 HTTP 调用的 Lambda A 以 ID 响应并继续从 API 异步获取资源并将其存储到 S3
    2. 由 S3 上传事件调用的 Lambda B 下载上传的资源,对其进行更改,将更改后的副本存储到 S3,最后使用更改后资源的文件名作为不同的重复数据删除 ID 将消息推送到 FIFO SQS 队列中
    3. 由 CloudWatch 调度程序调用的 Lambda C 轮询 FIFO SQS 队列,并在收到新消息时从 S3 获取指定的更改资源并将其提交给其他 API

    通过这种安排,即使 Lambda B 偶尔会被同一个 S3 上传事件执行两次或更多次,也不会造成任何损害,因为 FIFO SQS 队列会在流到达 Lambda C 之前为您处理重复数据删除。

    【讨论】:

    • 我觉得 FIFO 队列不能触发 lambdas 很烦人。这基本上正是我所需要的。我的触发过程计算量很大,我看不出为什么在标准 SQS 队列可以触发 lambdas 时我必须允许多次调用的理由
    • 作为更新,AWS recently announced 支持将 SQS FIFO 作为 Lambda 事件源。但是,当用作 Lambda 触发器时,它们不能保证一次性交付,因此上述工作流程仍然是必要的 AFAIK。
    【解决方案4】:

    AWS Step 函数适合您:https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html

    您将根据之前的执行输出执行您想要的步骤。 每个任务/步骤只需要在想要的“状态”中正确输出一个 json。

    https://docs.aws.amazon.com/step-functions/latest/dg/concepts-states.html

    根据状态,您的工作流程将继续进行。您可以轻松创建工作流并触发 lambda 或 ECS 任务。 ECS 任务是您自己的“lambda”环境,运行不受 AWS Lambda 环境的限制。

    使用 ECS 任务,您可以在裸机、您自己的 EC2 机器或 ECS 上的 ECS Docker 容器中运行,因此具有无限的资源可扩展限制。 与限制非常严格的 Lambda 相比:500Mb 磁盘、执行时间受限等。

    【讨论】:

      猜你喜欢
      • 2019-08-01
      • 2020-11-06
      • 1970-01-01
      • 1970-01-01
      • 2018-09-07
      • 2018-06-18
      • 2019-11-21
      • 2014-07-14
      • 1970-01-01
      相关资源
      最近更新 更多