delete_message_batch 并没有真正从 SQS 队列中删除消息

delete_message_batch doesn't really delete messages from SQS queue

我使用的是标准 Amazon SQS 队列。使用 python3 中的 boto3 库与 SQS 交互。以下是我接收消息然后删除它们的代码:

from boto3.session import Session
boto3_session = Session(region_name=SQS_REGION_NAME, aws_access_key_id=SQS_ACCESS_ID,
                                aws_secret_access_key=SQS_ACCESS_KEY)
sqs = boto3_session.client('sqs')

response = sqs.receive_message(
    MessageAttributeNames=[
        'EventToReport',
    ],
    QueueUrl=queue_url,
    MaxNumberOfMessages=10,
    VisibilityTimeout=0,
    WaitTimeSeconds=0
)
messages = response['Messages']
receipt_handles = [{'Id': str(index), 'ReceiptHandle': msg['ReceiptHandle']} for index, msg in enumerate(messages)]
sqs.delete_message_batch(QueueUrl=queue_url, Entries=receipt_handles)

这 returns 成功响应:

{'Successful': [{'Id': '0'}, {'Id': '1'}, {'Id': '2'}, {'Id': '3'}, {'Id': '4'}, {'Id': '5'}, {'Id': '6'}, {'Id': '7'}, {'Id': '8'}, {'Id': '9'}], 'ResponseMetadata': {'RequestId': 'bb28855b-6522-5a1e-a649-d7b3fdabfebe', 'RetryAttempts': 0, 'HTTPStatusCode': 200, 'HTTPHeaders': {'content-length': '1008', 'connection': 'keep-alive', 'server': 'Server', 'date': 'Mon, 29 Jan 2018 03:34:33 GMT', 'content-type': 'text/xml', 'x-amzn-requestid': 'bb28855b-6522-5a1e-a649-d7b3fdabfebe'}}}

但是当我查看我的 SQS 管理控制台时,我可以看到 none 条消息被删除了!消息的可见性超时为 30 秒。

我将队列的可见性超时增加到 30 分钟,现在只有 1 条消息被删除,尽管响应相同!

我知道删除需要一些时间才能完成,所以我每次都等了 2-3 分钟,但消息仍在队列中...我是否以错误的方式调用了 API?据我所知,这是使用 boto3.

调用 sqs api 的正确方法

我终于找到了我的代码的问题。尽管我在 sqs 控制台中描述了可见性超时,但我的 get 请求覆盖了它,所以我只是从我的 receive_message 代码中删除了以下两行:

VisibilityTimeout=0,
WaitTimeSeconds=0

现在工作正常。

SQS 如何处理删除请求

描述了为什么设置 VisibilityTimeoutWaitTimeSeconds 会影响删除方法的行为。

Note

The ReceiptHandle is associated with a specific instance of receiving a message. If you receive a message more than once, the ReceiptHandle is different each time you receive a message. When you use the DeleteMessage action, you must provide the most recently received ReceiptHandle for the message (otherwise, the request succeeds, but the message might not be deleted).

For standard queues, it is possible to receive a message even after you delete it. This might happen on rare occasions if one of the servers which stores a copy of the message is unavailable when you send the request to delete the message. The copy remains on the server and might be returned to you during a subsequent receive request. You should ensure that your application is idempotent, so that receiving a message more than once does not cause issues.

这部分是最重要的: ReceiptHandle 与接收消息的特定实例相关联。如果您不止一次收到一条消息,每次收到消息时 ReceiptHandle 都是不同的。 这意味着如果该体系结构允许单个队列的多个消费者,则很可能在一个消费者处理消息时它被另一个消费者再次检索,并且要删除消息的 ReceiptHandle 已经不同了。第二个重要的事情是请求成功,但消息可能不会被删除。 SQS 不会让您知道邮件没有被删除。

设置有何帮助

以及为什么他们无论如何都帮不上忙

检索之间的延迟越短,消息在处理过程中被另一个消费者“意外”检索到的可能性就越高。但是,如果消费者进行长轮询并缓存 ReceiptHandles,则所需的 VisibilityTimeout 应该太长并且具有如此大的价值,这将减慢轮询速度,使其几乎是顺序的。

解决方案

如果您不能在检索后立即删除消息,则应在单独的消费者中删除已处理的消息,否则,它有可能成为孤儿(永远不会被删除的消息)处理并再次删除)在队列中。