【问题标题】:Trigger another lambda after a week of first lambda execution在第一次 lambda 执行一周后触发另一个 lambda
【发布时间】:2020-11-06 15:26:41
【问题描述】:

我正在编写一个代码,其中 Lambda 函数 1(称为 L1)对来自 SQS 队列的消息执行。我想在 L1 完成一周后执行另一个 lambda(称为 L2)并希望将 L1 的输出传递给 L2。

执行环境:Java

对于我的应用程序,我们预计 L1 上每天有大约 10k 个请求。并且对 L2 的请求数量相同。

如果运行一周,我们可以在高峰期有大约 70k 的活跃执行。

我尝试过的事情:

带有 cron 的 Cloudwatch 事件: 我可以安排一个具有指定时间或日期的 cron,这将触发 L2。但我找不到通过预定 Cloudwatch 事件传递输入的方法。

具有新规则的 Cloudwatch 事件: 在第一个 lambda 结束时,我可以创建一个具有指定时间和指定输入的新 cloudwatch 规则。但这将创建尽可能多的规则(就我而言,每天可能有大约 10k 条新的 cloudwatch 规则)。不确定这是否是一种好的做法,甚至是否受支持。

步进函数: 目前有两种类型的步进函数。 标准:支持等待一年,但任何时候只支持 25k 主动执行。不会扩展,因为我的应用程序在第一周结束时已经有 70k 活跃执行。 https://docs.aws.amazon.com/step-functions/latest/dg/limits.html

Express: 对主动执行的次数没有限制,但最多支持 5 分钟的执行。之后会超时。 https://docs.aws.amazon.com/step-functions/latest/dg/express-limits.html

【问题讨论】:

  • 什么是时间分辨率 - 即 1 周后的准确度必须是多少?
  • 至少要晚 1 周。
  • 在我的回答中添加了一种新的处理方式。

标签: amazon-web-services aws-lambda


【解决方案1】:

很容易创建一个新的 Cloudwatch 规则,将“一周后”的 Lambda 作为目标作为第一个 Lambda 的最后一步。您将设置一个带有 cron 的规则,该规则在 1 周内运行 1 次。然后,目标有一个输入字段。在控制台中它看起来像:

您没有指明您的编程环境,但您可以执行类似的操作(伪代码,基于 Java SDK v2):

String lambdaArn = "the one week from today lambda arn";
String ruleArn = client.putRule(PutRuleRequest.builder()
                .scheduleExpression("17 20 23 7 *")
                .name("myRule")).ruleArn();
Target target = TargetBuilder.builder().arn(lambdaArn).input("{\"message\": \"blah\"}").rule("myRule");
client.putTargets(PutTargetsRequest.builder().targets(target));

这将创建一个 Cloudwatch 事件规则,该规则运行一次,从今天开始 1 周,输入如图所示。

重大修改

根据您的新要求(至少 1 周后,成千上万的事件),我不会使用我上面描述的方法,因为发生的事情太多了。相反,我将拥有一个充当队列的事件数据库。 DynamoDB 或 RDS 数据库就足够了。在每次“主要”Lambda 运行结束时,插入一个事件,其中包含下一次运行的日期和时间。例如,今天,7 月 18 日,我将插入 7 月 25 日。该表将类似于(PostgreSQL 语法):

create table event_queue (
    run_time        timestamp not null,
    lambda_input    varchar(8192),
);

create index on event_queue( run_time );

lambda_input 列包含您想要传递给“一周后”Lambda 的任何数据。在 PostgreSQL 中,您会执行以下操作:

insert into event_queue (run_time, lambda_input)
    values ((current_timestamp + interval '1 week'), '{"value":"hello"}');

每个数据库都有类似于显示的日期/时间函数的东西,或者执行此操作的代码并不糟糕。

现在,在 CloudWatch 中创建一个每小时运行一次的规则(可以调整分辨率)。它将触发一个“馈送”一个 SQS 队列的 Lambda。 Lambda 将查询数据库:

select * from event_queue where run_time < current_timestamp

并且,对于每一行,将一条消息放入一个 SQS 队列。它所做的最后一件事是使用相同的 where 子句删除这些“旧”消息。

另一方面,您有“一周后”的 Lambda,它们正在从 SQS 队列中获取事件。在将一组消息放入队列之前,这些 Lambda 是空闲的。那时他们启动并清空队列,做“一周后”Lambda应该做的任何事情。

通过每小时运行一次“feeder”Lambda,您基本上可以捕获 1 周加上最多 1 小时的所有内容。您运行它的频率越低,您的“一周后” Lambda 必须做的工作就越多,相反,每分钟运行一次会增加数据库的负载,但会从一周后的 Lambda 中删除它。

假设“馈线”Lambda 可以跟上,这应该可以很好地扩展。 10k 个事务/24 小时只有 416 个事务,读取数据库和创建消息应该非常快。即使每天将其扩展 10 到 100k,仍然只有约 4000 行和消息,这应该是非常可行的。

【讨论】:

  • 对于我的应用程序,我们每天可以有大约 10k 个请求来启动第一个 lambda,并且它可能会不断增加。那么,如果我这样做,它不会在 CloudWatch 中创建尽可能多的规则吗?不确定这是否是一个好习惯。每天有 10k 个请求,我们在 cloudwatch 中可能有大约 70k 条规则。
  • 不是使用计划的 Lambda 函数检查 DDB 表,而是在插入项目时设置项目 expiration date。然后使用带有 Lambda 触发器的 DDB 流,应在对象过期时调用该函数。注意:DDB 的替代方案可能是使用 S3,应用相同的逻辑。
  • 我认为这会奏效。我将使用 stdunbar 和 Paradigm 建议的方法组合。
【解决方案2】:

Cloudwatch 更适合 cron 作业。要在特定时间戳或 X 时间后触发某事,我建议改用 Step Functions

您可以通过使用带有Wait State 的状态机(您可以根据您的输入告诉它等待多长时间)和您的Lambda Task State 来实现您的用例。它将类似于此example

【讨论】:

  • 我尝试了 Step 功能。但这有它自己的局限性。标准工作流只能有 25000 次活动执行,而 express 只支持 5 分钟的最大执行时间。而且我需要两个(即可能有超过 25k 次执行,因为延迟是一周)和 1 周的等待时间。
猜你喜欢
  • 2020-08-07
  • 2018-06-18
  • 1970-01-01
  • 2020-01-07
  • 2019-11-21
  • 2018-12-12
  • 2013-02-11
  • 1970-01-01
  • 2018-01-08
相关资源
最近更新 更多