【问题标题】:How to prevent AWS Lambda from deleting message from SQS queue automatically and instead delete it programmatically?如何防止 AWS Lambda 自动从 SQS 队列中删除消息,而是以编程方式将其删除?
【发布时间】:2020-12-30 03:46:55
【问题描述】:

将文件添加到我的 S3 存储桶时,会触发 S3PUT 事件,将消息放入 SQS。我已将 Lambda 配置为在消息可用时立即触发。

在 lambda 函数中,我发送 API 请求以在 ECS Fargate 容器上运行任务,其中环境变量包含从 SQS 接收的消息。在容器中,我使用消息从 S3 下载文件,进行处理,成功处理后我希望从 SQS 中删除消息。

但是,在我的 lambda 执行后,该消息会自动从 SQS 中删除。 有什么方法可以将 lambda 配置为不自动删除 SQS 消息(除了引发异常并故意使 lambda 失败),以便我可以以编程方式从容器中删除消息?

更新: 考虑一下我希望实现的这种情况。

  1. 消息进入 SQS 队列
  2. Lambda 获取消息并运行 ECS API 并在不从队列中删除消息的情况下完成。
  3. 消息正在进行中。
  4. ECS 容器运行任务并在成功处理后从队列中删除 msg。 如果容器失败,在可见性超时后,消息将重新进入队列并再次触发 lambda,循环将从第 1 步开始重复。
  5. 如果容器失败超过一定次数,那么消息才会从 in-flight 发送到 DLQ。

这一切目前只有在我故意在 lambda 上引发异常并且我正在寻找类似的解决方案而不这样做时才有效。

【问题讨论】:

  • 将消息副本添加到正在进行的 SQS 队列(或 DynamoDB 表)中,稍后在相关任务完成时将其删除。
  • @jarmod 是的,我想到了,但万一我的容器任务失败,我也希望它用该消息重试任务。如果失败,则消息将仅位于 SQS 中。如果我引发异常并故意使 lambda 失败,所有这些都有效,但我认为这不是最佳实践
  • 您可以添加一个计划的 Lambda,根据需要每天多次查询正在进行的队列(或 DB),确定给定的工作流是否已超过其最大 TTL,然后重新添加消息发送到原始 SQS 队列。
  • 如果 Lambda 函数发回失败信号,它可能会将消息放回队列中。 (或者,更准确地说,消息会在隐身期到期后重新出现。)您可以将死信队列配置为在给定次数的尝试后激活。

标签: amazon-web-services amazon-s3 aws-lambda amazon-sqs aws-fargate


【解决方案1】:

该行为是有意的,只要将 SQS 配置为 Lambda 触发器,一旦函数返回(即完成执行),消息就会自动删除。

在我看来,要实现您所描述的行为,您有 4 个选项:

  • 将 SQS 作为 Lambda 触发器移除,改为按计划执行 Lambda 函数并自行轮询队列。 lambda 将读取可用的消息,但除非您明确删除它们,否则它们将在其可见性超时到期后再次变为可用。您可以通过 CloudWatch 计划来实现这一点。
  • 将 SQS 作为 Lambda 触发器删除,而是显式执行 Lambda 函数。与上述类似,但不是一直按计划执行,Lambda 函数可以由消息的生产者本身触发。
  • 保留 SQS Lambda 触发器并将消息存储在备用 SQS 队列中(如 @jarmod 在上面的评论中所建议的那样)。
  • 将消息的生产者配置为将消息发布到 SNS 主题并将 2 个 SQS 队列订阅到该主题。两个队列之一将触发 Lambda 函数,另一个将由您的 ECS 任务使用。

更新

根据提供的新信息,您还有另一种选择:

让事件流保持原样,让 Lambda 删除 SQS 中的消息。然后,在您的 ECS 任务中,处理故障状态并将具有相同有效负载/正文的新消息放入 SQS。这将允许您无限期地重试。

没有理由 SQS 消息必须完全相同,您感兴趣的是正文/有效负载。

您可能需要考虑添加一种机制来设置这些重试的限制并将消息发布到 DLQ。

【讨论】:

  • -关于您的第二点,如果我由消息本身的生产者(S3 PUT 事件)触发将消息放入 SQS 的 Lambda 函数,那么不会有可能lambda 函数在消息放入 SQS 之前执行? -关于您的第 3 点和第 4 点,如果我的容器任务失败,我希望它使用该消息重试任务。如果失败,则消息将仅位于 SQS 中。
  • 在 #2 中,我假设您的生产者本身就是一个进程,在 S3 事件的情况下,您不能同时做这两件事(在 SQS 中放置一条消息并触发 Lambda)。假设您只触发您的 Lambda 函数,您需要 SQS 做什么?将使用与 S3 上传事件相同的内容调用 lambda。基本上与 SQS 中的结果相同。在这种情况下,您的架构将如下所示 S3 -> S3 Put 事件 -> Lambda Fn -> SQS msg -> ECS。
  • 不管我的所有回答,甚至是您的原始问题,ECS 都不会像 Lambda 函数那样为您处理重试。如果您的 ECS 任务失败,您将不得不自行重试。
  • SQS msg -> ECS 这将如何工作?我需要一个调用 ECS API 的 Lambda 函数来运行任务。
  • 考虑我希望实现的这个场景。 1)消息进入 SQS 队列 2)Lambda 获取消息并运行 ECS API 并完成而不从队列中删除消息。 3) 消息在飞行中。 4)ECS容器运行任务并在成功处理后从队列中删除msg。如果容器失败,在可见性超时后,消息将重新进入队列并再次触发 lambda,循环将从步骤 1 开始重复。 5)如果容器失败超过一定次数,只有这样消息才会消失从机上到 DLQ。
猜你喜欢
  • 2020-03-24
  • 1970-01-01
  • 2016-04-29
  • 2018-06-21
  • 2021-03-25
  • 2020-07-10
  • 2015-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多