如何检查消息是不是即将通过 MessageRetentionPeriod?

Posted

技术标签:

【中文标题】如何检查消息是不是即将通过 MessageRetentionPeriod?【英文标题】:How can I check if a message is about to pass the MessageRetentionPeriod?如何检查消息是否即将通过 MessageRetentionPeriod? 【发布时间】:2015-04-03 10:28:44 【问题描述】:

我有一个使用 SQS 对作业进行排队的应用。理想情况下,我希望每项工作都能完成,但有些工作会失败。有时重新运行它们会起作用,有时它们会一直失败,直到达到保留期。 .我想尽可能长时间地将失败的作业保留在队列中,为他们提供最大可能的成功机会,所以我不想设置maxReceiveCount。但我确实想检测作业何时达到MessageRetentionPeriod 限制,因为我需要在作业完全失败时发送警报。目前我的最长保留期为 14 天,但到那时仍有一些工作无法完成。

有没有办法检测作业何时即将到期,并从那里将其发送到死信队列以进行额外处理?

【问题讨论】:

【参考方案1】:

在您遵循以下我的建议和assuming I've done the math for periods correctly 之前,如果您少于每 20 分 9 秒检查一次消息,则最好使用enabling a redrive policy on the queue。

SQS 的“重新驱动策略”允许您在达到阈值接收次数后将消息迁移到死信队列。 AWS 允许的最大接收数为 1000,超过 14 天,每次接收大约需要 20 分钟。 (为简单起见,假设您的作业从不错过读取队列消息的尝试。您可以调整数字以建立对失败的容忍度。)

如果您检查的频率高于此,则需要实施以下解决方案。


您可以在处理消息时检查此“截止日期”(当作业即将到期时),如果消息已超过您放弃的时间,则将消息发送到死信队列。

要添加到当前例程的伪代码:

致电 GetQueueAttributes 以获取队列的消息保留期计数(以秒为单位)。 调用ReceiveMessage 将消息拉出队列。确保明确请求 SentTimestamp 可见。 Foreach 消息, 通过将邮件保留期添加到发送的时间戳来查找邮件的到期时间。 通过从邮件的到期时间中减去您想要的时间量来创建您的截止日期。 将截止日期与当前时间进行比较。如果截止日期已过: 致电SendMessage 将您的消息发送到死信队列。 致电DeleteMessage 将您的消息从您正在处理的队列中删除。 如果截止日期尚未过去: 正常处理作业。

这是 Powershell 中的示例实现:

$queueUrl = "https://sqs.amazonaws.com/0000/my-queue"
$deadLetterQueueUrl = "https://sqs.amazonaws.com/0000/deadletter"

# Get the message retention period in seconds
$messageRetentionPeriod = (Get-SQSQueueAttribute -AttributeNames "MessageRetentionPeriod" -QueueUrl $queueUrl).Attributes.MessageRetentionPeriod

# Receive messages from our queue.  
$queueMessages = @(receive-sqsmessage -QueueUrl $queueUrl -WaitTimeSeconds 5 -AttributeNames SentTimestamp)

foreach($message in $queueMessages)

    # The sent timestamp is in epoch time.
    $sentTimestampUnix = $message.Attributes.SentTimestamp

    # For powershell, we need to do some quick conversion to get a DateTime.
    $sentTimestamp = ([datetime]'1970-01-01 00:00:00').AddMilliseconds($sentTimestampUnix)

    # Get the expiration time by adding the retention period to the sent time.
    $expirationTime = $sentTimestamp.AddDays($messageRetentionPeriod / 86400 )

    # I want my cutoff date to be one hour before the expiration time.
    $cutoffDate = $expirationTime.AddHours(-1)

    # Check if the cutoff date has passed.
    if((Get-Date) -ge $cutoffDate)
    
        # Cutoff Date has passed, move to deadletter queue

        Send-SQSMessage -QueueUrl $deadLetterQueueUrl -MessageBody $message.Body

        remove-sqsmessage -QueueUrl $queueUrl -ReceiptHandle $message.ReceiptHandle -Force
    
    else
    
        # Cutoff Date has not passed. Retry job?
    

这将为您处理的每条消息增加一些开销。这还假设您的消息处理程序将在截止时间和到期时间之间接收消息。确保您的应用程序足够频繁地轮询以接收消息。

【讨论】:

这是有道理的,但你最后一段总结了我的问题。这个应用程序的工作量非常突发,我最终可能会在队列中处理 10,000 个作业,所有这些都需要多次尝试才能成功,或者我将只有几个作业在队列中。我不能只设置一个“放弃时间”,然后无论如何都会失败。它可能太早或太晚。我希望能够在即将被删除时更可靠地捕获作业,也许是 SQS 功能? 不,SQS 中没有这方面的功能。 MessageRetentionPeriod 是队列的一个属性,并没有真正在每个消息级别定义,以便您可以挽救这些消息。听起来您需要运行一个额外的作业:在某个时间间隔 t 内,检查队列中的每条消息,选择在此轮询作业再次运行之前将被删除的消息,并以完全相同的方式销毁/重新创建这些消息内容。这允许解决保留期限,并允许您的消息的内容无限期地留在队列中。

以上是关于如何检查消息是不是即将通过 MessageRetentionPeriod?的主要内容,如果未能解决你的问题,请参考以下文章

通过 firebase 云消息检查设备是不是离线

如何在特定时间通过 websocket 发送消息

如何检查消息的作者是不是是 Discord 机器人?

如何检查消息是不是传递到任何单个队列

如何检查消息是不是存在? (discord.js)

如何检查消息是不是在后台与应用程序挂起