我正在开发一个应用程序,其工作流程通过使用boto在SQS中传递消息来管理。
我的SQS队列逐渐增长,我无法检查它应该包含多少元素。
现在我有一个守护进程定期轮询队列,并检查我是否有一组固定大小的元素。例如,请考虑以下“队列”:
q = ["msg1_comp1", "msg2_comp1", "msg1_comp2", "msg3_comp1", "msg2_comp2"]
现在我想在某个时间点检查队列中是否有“msg1_comp1”,“msg2_comp1”和“msg3_comp1”,但我不知道队列的大小。
查看API后,您似乎只能获得1个元素,或队列中固定数量的元素,但不是全部:
>>> rs = q.get_messages()
>>> len(rs)
1
>>> rs = q.get_messages(10)
>>> len(rs)
10
答案中提出的建议是在循环中获取10个消息,直到我什么也得不回来,但SQS中的消息具有可见性超时,这意味着如果我从队列中轮询元素,它们将不会真的被删除了,它们只会在短时间内隐身。
有没有一种简单的方法来获取队列中的所有消息,而不知道有多少消息?
答案 0 :(得分:16)
在while循环中调用q.get_messages(n)
:
all_messages=[]
rs=q.get_messages(10)
while len(rs)>0:
all_messages.extend(rs)
rs=q.get_messages(10)
此外,dump won't support more than 10 messages:
def dump(self, file_name, page_size=10, vtimeout=10, sep='\n'):
"""Utility function to dump the messages in a queue to a file
NOTE: Page size must be < 10 else SQS errors"""
答案 1 :(得分:12)
我一直在使用AWS SQS队列提供即时通知,因此我需要实时处理所有消息。以下代码将帮助您有效地将(所有)消息出列并在删除时处理任何错误。
注意:要删除队列中的消息,您需要删除它们。我使用了更新的boto3 AWS python SDK,json库和以下默认值:
import boto3
import json
region_name = 'us-east-1'
queue_name = 'example-queue-12345'
max_queue_messages = 10
message_bodies = []
aws_access_key_id = '<YOUR AWS ACCESS KEY ID>'
aws_secret_access_key = '<YOUR AWS SECRET ACCESS KEY>'
sqs = boto3.resource('sqs', region_name=region_name,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key)
queue = sqs.get_queue_by_name(QueueName=queue_name)
while True:
messages_to_delete = []
for message in queue.receive_messages(
MaxNumberOfMessages=max_queue_messages):
# process message body
body = json.loads(message.body)
message_bodies.append(body)
# add message to delete
messages_to_delete.append({
'Id': message.message_id,
'ReceiptHandle': message.receipt_handle
})
# if you don't receive any notifications the
# messages_to_delete list will be empty
if len(messages_to_delete) == 0:
break
# delete messages to remove them from SQS queue
# handle any errors
else:
delete_response = queue.delete_messages(
Entries=messages_to_delete)
答案 2 :(得分:6)
我的理解是,SQS服务的分布式特性几乎使您的设计变得不可行。每次调用get_messages时,您都会与另一组服务器通信,这些服务器将包含部分但不是全部的消息。因此,不可能“不时检查”以设置特定的消息组是否准备就绪,然后只接受这些消息。
您需要做的是持续轮询,在到达时收集所有消息,并将它们本地存储在您自己的数据结构中。每次成功获取后,您都可以检查数据结构,以查看是否收集了一整套消息。
请记住,消息 将无序到达,而某些消息将交付两次,因为删除必须传播到所有SQS服务器,但后续获取请求有时会超出删除消息。
答案 3 :(得分:3)
我在cronjob中执行此操作
from django.core.mail import EmailMessage
from django.conf import settings
import boto3
import json
sqs = boto3.resource('sqs', aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
region_name=settings.AWS_REGION)
queue = sqs.get_queue_by_name(QueueName='email')
messages = queue.receive_messages(MaxNumberOfMessages=10, WaitTimeSeconds=1)
while len(messages) > 0:
for message in messages:
mail_body = json.loads(message.body)
print("E-mail sent to: %s" % mail_body['to'])
email = EmailMessage(mail_body['subject'], mail_body['message'], to=[mail_body['to']])
email.send()
message.delete()
messages = queue.receive_messages(MaxNumberOfMessages=10, WaitTimeSeconds=1)
答案 4 :(得分:0)
下面的代码应该可以解决问题。对不起它在C#中,但它不应该很难转换为python。字典用于清除重复项。
public Dictionary<string, Message> GetAllMessages(int pollSeconds)
{
var msgs = new Dictionary<string, Message>();
var end = DateTime.Now.AddSeconds(pollSeconds);
while (DateTime.Now <= end)
{
var request = new ReceiveMessageRequest(Url);
request.MaxNumberOfMessages = 10;
var response = GetClient().ReceiveMessage(request);
foreach (var msg in response.Messages)
{
if (!msgs.ContainsKey(msg.MessageId))
{
msgs.Add(msg.MessageId, msg);
}
}
}
return msgs;
}
答案 5 :(得分:0)
注意:这不是对问题的直接回答。
相反,它是@TimothyLiu's answer的增强,假设最终用户使用Boto
包(又名Boto2)而不是Boto3
。这段代码是&#34; Boto-2-ization&#34; his answer中提到的delete_messages
来电
Boto
的{{1}}(2)调用,其中delete_message_batch(messages_to_delete)
是messages_to_delete
对象,其键:值对应dict
:id
对返回< p>
属性错误:&#39; dict&#39;对象没有属性&#39; id&#39;。
似乎receipt_handle
期望delete_message_batch
类对象;复制Boto source for delete_message_batch
并允许其使用非Message
对象(ala boto3)也会失败,如果您要删除超过10条&#34;的消息&#34;一次。所以,我不得不使用以下解决方法。
来自here
的eprint代码Message