SQS - 30分钟的投递延迟

20

2
请查看 https://alestic.com/2015/05/aws-lambda-recurring-schedule/ 以获取每日定时任务的信息。 - jarmod
1
使用AWS:SQS来模拟cron job是一个不好的想法。AWS:SQS提供了最终交付,但不能保证消息会在您指定的delay_seconds之后准确地传递。可能会多花一秒钟或更长时间(虽然极为罕见),也可能会出现重复传递的情况。使用可见性超时字段也是如此。请小心。 - anshul410
8个回答

28

最简单的方法如下:

SQS.push_to_queue({perform_message_at : "Thursday November 2022"},delay: 15 mins)

您的 worker 内部

message = SQS.poll_messages
if message.perform_message_at > Time.now
   SQS.push_to_queue({perform_message_at : "Thursday November 
   2022"},delay:15 mins)
else
   process_message(message)
end

基本上将消息推回队列并设置最大延迟,仅在其处理时间小于当前时间时才对其进行处理。

希望对你有帮助。


@flicflac,队列中的消息总数永远不会超过要延迟的作业数量,不会有任何堵塞的问题。您是提到的网站的创始人或推广者之一吗?如果是付费服务,澄清一下你的立场会很好。谢谢! - Algorini
2
嘿@user2076066,抱歉我应该澄清一下。我遇到了与您和OP相同的问题,并正在构建API来解决这个确切的问题。关于拥堵的问题,所提出的解决方案的主要问题是消费者只应有一个责任-处理消息。在这里,它有两个责任,重新排队延迟的消息和处理消息。随着时间的推移,如果您有长时间的延迟,它会花费更多的时间重新排队延迟的消息,而不是履行其主要工作:处理消息。顺便说一句,我很想聊一些时间,只是为了听听您的用例。 - flicflac
6
我的原始评论被删除了,但是我觉得我的观点依然重要。如果你将一条消息延迟一天,那么在使用这种解决方案时,这条消息可能会排队和重新排队大约100次,直到最终处理完成。这样的做法不利于扩展,并且AWS的成本可能非常昂贵。 - flicflac
另一个选项是您可以在 SQS 上配置延迟(无论是从控制台还是创建 SQL 时)。如果同一 SQS 有多个生产者/发布者,这可能非常有用。 - Athar
仅在应该执行时使用CRON作业推送消息有何反对意见? - Hugo

9

如何使用wait实用程序与sqs。 - Vishnu Mishra

8

可见性超时最多可以设置为12小时。我认为你可以编写一些代码,在处理消息时不要将其删除,下次处理该消息时已经过去了12小时。因此,使用一个消息和可见性超时为12小时的队列可以实现12小时的计划任务。


32
这不可扩展。在任何给定时间内,可以无形(也称为在飞行中)的信息数量有一个上限,即120,000条。 - Piyush Joshi
另一个问题在于,据我所知,隐形消息真的是无法被看到的,即使从Web控制台也一样。这使得诊断/监视/警报您的SQS队列变得更加困难。从这个意义上讲,我认为使用Cloudwatch或EventBridge才是解决这个问题的更适当的方法。 - Evren Kuzucuoglu

0
将消息重新排队到同一队列可能不是最佳路线。如果出现问题,看到一个满的队列可能会让人感到困惑(它应该是满的吗?还是消费者没有处理它们?)。当应在15分钟内处理消息时,消息可能应该只进入队列。否则,您将调用数千次调用以简单地重新排队消息。
我会执行以下操作:
Lambda工作程序1:接收新消息,如果物品应延迟超过15分钟,则存储在DynamoDB中,否则将消息排队。
Lambda工作程序2:每n(5?)分钟,轮询DynamoDB以查找应在下一个15分钟内处理的消息,并将带有正确延迟的消息排队。
只需添加索引即可快速查询按执行日期排序的消息,这应该可以覆盖每秒排队数千条消息的能力。如果您的吞吐量需求高于此,则可能不是最佳解决方案。

0

如果资源利用效率不是问题,那么对使用可见性超时队列进行微调可能会很有用。这可以让我们延迟最多12小时,但如果我们将消息切换到另一个队列,则可以延长时间。

Amazon SQS队列中的可见性超时功能为未从队列中删除的消息(如果消费者无法处理它)提供基于间隔的重试机制,默认设置为30秒。因此,相同的消息将在30秒间隔内不断出现在消费者面前,直到其从队列中删除为止。

SQS还提供了一种处理未从队列中删除的消息的方法,即使用死信队列,该队列将排队无法处理(或说未从主队列中删除)的消息。消息进入死信队列的重试次数是可配置的。

关键在于使用死信队列来处理而不是实际队列。

我们可以配置两个队列Q1和Q1-dead-queue。在默认可见超时设置为所需值的1次尝试后,Q1将具有Q1-dead-queue作为备份队列。

对于Q1的消费者只会消耗它(不进行处理),但不会从Q1中删除它。然后,此消息将等待配置的可见超时时间(最长可达12小时),并将被放入Q1-dead-queue中,死信队列的消费者现在可以及时处理它。

此外,可见超时时间也可以在消息级别上进行配置。

参考资料:

https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html

https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-dead-letter-queue.html


-1

两个想法。

  1. 未经测试。也许可以发布到没有SQS队列的SNS主题上。当需要传递时,将队列订阅到该主题上。(我没有尝试过,不确定是否会按预期工作)
  2. 将消息作为文件推送到中央存储(如S3)。创建一个工作程序,查看创建时间戳并决定是否将其发布到队列中。如果创建时间 >= 1天,则发布。

任何类型的工作者。我想到的是一个EC2虚拟机。 - Marc Young
Arun,AWS的弹性Beanstalk支持将工作实例直接链接到SQS队列。 - Ben Wheeler

-1

您可以通过在第一个队列上添加MaxReceives设置为1的DLQ来实现此操作。 在第一个队列上添加一个简单的Lambda函数,并通过Lambda函数使消息失败。因此,消息将自动移动到DLQ,然后您可以从DLQ中消费。 主队列和DLQ都可以具有最长15分钟的延迟,因此最终您将获得30分钟的延迟。

因此,您的消费者应用程序将在30分钟后接收到消息,而无需添加任何自定义逻辑。


-2
这对我们来说也是个挑战,我也没有找到一个完美的解决方案,所以最后我建立了一个服务来解决这个问题。显然这里涉及到自我推销,但是这个系统允许你规避DelaySeconds的限制,并且在大规模上设置任意的日期/时间。

https://anticipated.io

使用 Step Functions 工作时面临的一些挑战是注册机器的规模(如果您的系统有此要求)。如果您使用 EventBridge 来触发它们,您会耗尽允许的规则集(截至本文发布时,限制为 200)。例如:如果您需要每月设置 150,000 个任意事件,则很快就会遇到限制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接