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

时间:2015-02-04 02:01:07

标签: amazon-web-services amazon-sqs dead-letter

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

有没有办法检测作业即将到期的时间,并从那里将其发送到deadletter queue以进行其他处理?

1 个答案:

答案 0 :(得分:2)

在您按照我的建议和assuming I've done the math for periods correctly之前,如果您检查的消息少于每20分钟9秒,那么您的状况会更好enabling a redrive policy on the queue

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

如果您经常检查,则需要实施以下解决方案。


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

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

  • 致电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?
    }
}

这会为您处理的每条消息增加一些开销。这也假定您的消息处理程序将在截止时间和到期时间之间接收消息。确保您的应用程序经常轮询以接收消息。